2017-11-01 12 views
-1

チュートリアルのレッスンやここでのコードは、理解できません。誰か助けてくれますか?私はあなたの助けを感謝します。スタックでnasmを押してポップアップする

最初に関数sprintが呼び出され、 'sprint'関数でedx、ecx、ebx、eaxがスタックにプッシュされ、関数 'slen'が呼び出され、 ebxはスタックにプッシュされますが、私はこのステップを理解していません。ebxはすでにスタック上にあります。私は、ebxがsprint関数が呼び出された後のスタックの2番目の最後のスタックであることを知っています。 ここに2つのスタックがあるのでしょうか?または 誰かが私のために説明できますか?私はとても感謝しています。

最高点

functions.asm

;------------------------------------------ 
; int slen(String message) 
; String length calculation function 
slen: 
push ebx 
mov  ebx, eax 

nextchar: 
cmp  byte [eax], 0 
jz  finished 
inc  eax 
jmp  nextchar 

finished: 
sub  eax, ebx 
pop  ebx 
ret 


;------------------------------------------ 
; void sprint(String message) 
; String printing function 
sprint: 
push edx 
push ecx 
push ebx 
push eax 
call slen 

mov  edx, eax 
pop  eax 

mov  ecx, eax 
mov  ebx, 1 
mov  eax, 4 
int  80h 

pop  ebx 
pop  ecx 
pop  edx 
ret 


;------------------------------------------ 
; void exit() 
; Exit program and restore resources 
quit: 
mov  ebx, 0 
mov  eax, 1 
int  80h 
ret ' 

BLOCKQUOTE のHelloWorld-inc.asm

; Hello World Program (External file include) 
; Compile with: nasm -f elf helloworld-inc.asm 
; Link with (64 bit systems require elf_i386 option): ld -m elf_i386 helloworld-inc.o -o helloworld-inc 
; Run with: ./helloworld-inc 

%include  'functions.asm'        ; include our external file 

SECTION .data 
msg1 db  'Hello, brave new world!', 0Ah    ; our first message string 
msg2 db  'This is how we recycle in NASM.', 0Ah  ; our second message string 

SECTION .text 
global _start 

_start: 

mov  eax, msg1  ; move the address of our first message string into EAX 
call sprint   ; call our string printing function 

mov  eax, msg2  ; move the address of our second message string into EAX 
call sprint   ; call our string printing function 

call quit   ; call our quit function 
+0

関数は、関数または関数が使用するすべてのレジスタを保存する必要があります。 –

+0

なぜこれをCでタグ付けしましたか?私はアセンブリしか見ることができません。 – klutt

+0

しかし、sprintが呼び出された後、すでにebxがスタックにプッシュされていて、関数 'slen'で再びスタックにプッシュされるので、スタック上に2つのebxがあることを意味しますか?私はそれに興味がありません:( – khaco

答えて

2

2 FUNC独立しています(どちらもパブリックAPI関数を意味します)。 sprintが内部でslenを呼び出すのは、sprintから呼び出されたと仮定することはできません。ebxは既にそれによって保持されています。ebxがスタックに格納されていないユーザーコードから直接呼び出されることがあります。

したがって、両方の関数はコードの著者が選択したものです(私はそれらを頭から知ることはできませんし、どちらがどちらかと推測したくもありませんが、Linuxの場合、elf32を構築する場合はおそらく、標準のLinux 32b呼び出し規約(間違った推測、Irvine32 lib呼び出し規約のように見えます。eax以外のすべてのレジスタを保持していますが、これはPeter Cordesのコメントのおかげです)。つまり、どちらの関数も独立にいくつかのレジスタを保持して規約に準拠させる必要があり、一部のレジスタだけを自由に変更して修正された状態で返すことができます。

i「はEBXは」スプリント関数の後EAX後、今スタック上の第二の最後の一つであることを知っているように

と呼ばれ、それはどちらかの真実ではないです。 "スタック"は、あなたの.data.bssのセクションのように普通のコンピュータメモリです。それは、あなたのアプリプロセスのためのもう一つの予約メモリです。それをやや特殊なものにするのは、レジスタespの値であり、 "スタックの先頭"を指しています。

今、あなたはpush ebxを行う際に、命令(32ビット= 4バイト、pushは32Bモードで-4により、スタックポインタを移動理由です)アドレスesp-4でコンピュータのメモリにレジスタebxで32ビットの値を書き込み、そして意志ますespをその場所(つまりesp -= 4)を指すように更新します。

あなたの誤解の1つは "ebx is stored"です。上記の説明を再度読めば、スタックメモリには、ebxからの情報はないことがわかります。そして実際に次の命令pop eaxとして実行すると、その値はレジスタeaxに問題なく復元されます。esp += 4は、mov eax,ebxと似ていますが、スタックメモリを経由します(直接movよりはるかに遅い)。

もう一つの誤解は、「第2の最後のeax」です。 call命令自体は戻りアドレスをスタックにプッシュしますので、push ebxの後にスタックに値 "ebx"が含まれ、call slen、 "eax"、 "ebx"の後に次の命令でアドレスを次の命令で返します。

のように、正確に特定の命令が何をするのか確認するために、命令のリファレンスガイドを使用することを躊躇しないでください:

それが一般的ですシーズニングされたsmプログラマは、特にフラグが含まれている場合、またはmul/div/lods/stos/xlatb/...のような暗黙的なレジスタの使用について、特定の命令に関する仮定を検証する必要があります。命令の名前だけで推測しないでください。そのうちのいくつかは、常識よりもはるかにトリッキーです。

はまた、それは多くの多くの多くの多くは、より簡単にだけ、デバッガでこのコードを発射指示をステップオーバー、およびespとスタックメモリ内容の進化は、(それがどのように正確にpush/pop作品については、この答えの第二の部分をクリアする方法を自分自身を見ることです)。

+0

あなたの詳細な答えはありがとうございます! – khaco

+0

もう1つ質問がありますか? slenが呼び出された後will nextchar:実行されるか? – khaco

+0

元の質問または私の回答(つまり、何かはまだ分かりません)、そうですね、私は "新鮮な目"で私の答えを読むのは難しいので、私は "分かりやすい"ものを省略するかもしれません。質問が全く関係ない(新しいもの)場合は、Googleで検索するか、Google検索が失敗した場合は別の質問を投稿することができますが、私の好奇心のためにコメントに投稿しても構いませんが、 "google this and that"最悪の場合。 – Ped7g

関連する問題