まず第一に、私の心を吹いてくれてありがとう。私が最初にあなたのコードを見たとき、私はそれがまったく動作するとは思わなかった。それから私はそれを試し、あなたの結果を再現しました。今は私にとって理にかなっています。 :-)私はそれを説明しようとします。
まず、これを達成するためのより正気な方法を見てみましょう。その後のprintfを呼び出す前に、スタック上にその文字列のアドレスをプッシュする
section .data
string: db "Hey, is this thing on?", 0
:ASMファイルのデータ部分の文字列を定義します
push string
call printf
だから、最初のパラメータはprintfのしていること(最後のパラメータ呼び出しの前にスタックにプッシュされる)は、書式文字列へのポインタです。あなたのコードが行ったことは、文字列をスタックにプッシュし、続いてスタックポインタが文字列をポイントすることでした。
push '567'
push '123'
push esp
call printf
はNASMで組み立て、その後、objdumpのと逆アセンブル:
nasm string.s -f elf32 -o string.o
objdump -d -Mintel string.o
あなたを
次に、私は彼らが解体に追跡することが容易になるように、あなたの文字列を置換するつもりですこの場合、32ビットの16進数字0x333231に変換されて、例えば「123」を押す。完全な32ビットは0x00333231であることに注意してください。
3: 68 35 36 37 00 push 0x373635
8: 68 31 32 33 00 push 0x333231
d: 54 push esp
スタックを押すと、スタックポインタが減少します。 0x70の初期スタックポインタと仮定すると(簡単にするための工夫)、これはprintfのを呼び出す前に、スタックの状態です:
64: 68: 6c: 70:
68 00 00 00 31 32 33 00 35 36 37 00 ...
ので、印刷が呼び出されたとき、それは文字列ポインタとして最初のパラメータを使用して印刷を開始しますそれがNULL(0x00)を見るまで、文字を返します。
この例では、「123」(オリジナルの「sud」)のみが印刷されています。
だから、 "123"の代わりに "1234"を押してみましょう。これは、値0x34333231をプッシュしていることを意味します。
64: 68: 6c: 70:
68 00 00 00 31 32 33 34 35 36 37 00 ...
今すぐスタック上のもの2列の間にはNULLギャップが存在しないと、この例では「1234567」を印刷します(または、あなたのオリジナルの「sudobor」):printf関数を呼び出す場合、スタックは、今のように見えます。
含意:「567」の代わりに「5678」を押してみてください。おそらくセグメンテーションフォルトが発生するでしょう。なぜなら、printfは読み込み許可を持たないメモリを読み込もうとするまで、文字を読み続けるだけです。また、4文字以上の文字列(「プッシュ '12345'」など)を押してみてください。アセンブラは、32ビットの数値に変換できないため、あなたを許可しません。
終了文字列をNULLにする必要がありますか? – Jeff
@ Jeff:明示的にNULLを追加する必要があると思いました。しかし、上記のコードはうまくいきました。おそらく、正しい場所に別のNULLがありました。純粋に偶然にも。 –
テストとして、最初の文字列の直後に別の文字列を宣言し、まだ期待どおりに動作するかどうかを確認します。私はヌルターミネーターを含んでいて、それが必要かどうかわからないでしょう。 – Jeff