2012-03-12 8 views
0

次の例でprintfを使って、何が起こっているのか説明できるのであれば、nasmとgccでコンパイルすることに感謝します。 「sud」がスクリーンにのみ印刷されているのはなぜですか?私は理解していない、また、なぜ私は "プッシュ 'と"プッシュ'と "交換すると、"スドボールは、画面に印刷されている "プッシュ 'sudo'? 誰かが、なぜ私はespをプッシュする必要があるのか​​説明できますか?それはnullですか、それはprintfの文字列の最後にある必要がありますか? ありがとうございます。Printf in Nasmの動作

section .data 

section .text 
    global start 
    extern printf 

start: 
    push ebp   
    mov  ebp, esp 
    push 'bor' 
    push 'sud' 
    push esp 
    call printf 
    mov  esp, ebp 
    pop  dword ebp 

    ret 

これでCファイル:

これはstring.sファイルです

#include <stdio.h> 
#include <stdlib.h> 
extern void start(); 
int main(void) { 
    start(); 

}

答えて

6

まず第一に、私の心を吹いてくれてありがとう。私が最初にあなたのコードを見たとき、私はそれがまったく動作するとは思わなかった。それから私はそれを試し、あなたの結果を再現しました。今は私にとって理にかなっています。 :-)私はそれを説明しようとします。

まず、これを達成するためのより正気な方法を見てみましょう。その後の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ビットの数値に変換できないため、あなたを許可しません。

+0

終了文字列をNULLにする必要がありますか? – Jeff

+0

@ Jeff:明示的にNULLを追加する必要があると思いました。しかし、上記のコードはうまくいきました。おそらく、正しい場所に別のNULLがありました。純粋に偶然にも。 –

+0

テストとして、最初の文字列の直後に別の文字列を宣言し、まだ期待どおりに動作するかどうかを確認します。私はヌルターミネーターを含んでいて、それが必要かどうかわからないでしょう。 – Jeff