book · csapp · 2016-08-24 · yuex

可能你已经比较熟悉 asm 函数调用的参数传递和地址跳转了,不过这里还是做一个简单的概 述。毕竟这是最基本的程序单元。

地址跳转

asm 中的地址跳转是通过 callret 进行的,但经常容易忽略的一个事实是

call 会将下一条指令的地址 (pc) 压栈
ret 会从栈上弹出一个地址到 pc

也就是说这两条指令都会导致栈指针的变化。在 32 位系统中,由于参数传递是通过压栈进 行的,要注意的是 call 一般都是在参数传递压栈之后(也必须这样),所以函数调用的返 回地址总是紧临被调用函数的 stack frame。

在 32 位系统中,在每次调用后,被调用函数一般还要维护 esp 和 ebp。一般都是将 ebp 压到栈 上,紧临返回地址。leave 是一个复合指令,用于弹栈以恢复 ebp。

参数传递

32 位系统中是依靠压栈进行参数传递的。而在 64 位系统中,小于等于六个的参数是通过寄 存器传递的,这就涉及一个顺序问题。一般是按照以下顺序传递参数的

64 位参数传递顺序:rdi, rsi, rdx, rcx, r8, r9

这里有一个助记法,屌丝屌操 69(dsdc89)。心里记住就好,别声张,都是文化人 ……

函数返回值无论 32 位还是 64 位都是一样的

 函数返回值:rax or eax

另外需要注意的是,intel 架构中浮点数的运算是通过单独的运算单元进行的,而不是通过 ALU。因此

 浮点型参数传递会使用单独的浮点寄存器进行,不会占用 ALU 的参数传递名额和顺序

特殊指定提要

AT&T 风格的 asm 有些指令不太好记,这里简单提要一下

memory access: imm(ra, rb, mul) = ra + rb * mul + imm
lea imm(ra, rb, mul), dst: 不需要 src 是有效地址,一般用于优化加乘法计算
test sec, fir: 比较并设置 cc,之后使用条件跳转进行条件判断
               需要注意条件跳转中的顺序是 fir ?? sec,刚好反过来
if cond: 一般是 cond false 跳转,cond true falls through
         这样可以保证有 else 和无 else 语句时 asm 码结构一致

-EOF-