Assemblyメモ

アセンブリに関していくつか。絶対に忘れそうなことをメモ。

関数呼び出し時のレジスタのconvention

ここを見よ。レジスタの保存とかを気にするなら結局setjmp/longjmpを使うのが一番ラクという説はある。

push/pop

pushは、rsp - 0x8に値を置き、rspをデクリメントする。逆にpopは、rspの値を読み、rspをインクリメントする。例えば

push rax

mov qword ptr [rsp - 0x8], rax
sub rsp, 0x8

と等価だし、

pop rax

mov rax, qword ptr [rsp]
add rsp, 0x8

と等価。

関数呼び出し

callは、戻り先のアドレスをpushし、指定アドレスにjmpする。jmpされた先では、通常

push rbp
mov rbp, rsp

が一番頭で実行される。元のrspは呼び出し元のスタックトップであり、そこより下位のアドレスは使用されていないことが保証されているので、rbpをそこに更新する。ただし、元のrbpを保存しておく。

leave/ret命令

leaveは。rsprbpの値にし、新しいスタックトップにある値(=qword ptr [rbp])をrbppopする。 つまり、

mov rsp, rbp
pop rbp

と等価。

push rbp
mov rbp, rsp

の逆命令ですね。leaveを呼ぶと、現在のスタックトップはcallで積まれた呼び出し先アドレスになっている。retを呼ぶとその値がpopされ、そこにjmpする。つまり、ret

pop rax
jmp rax

と等価。

Comments

comments powered by Disqus