X86 64 汇编要注意的地方

1)

不可能对MOV的两个参数使用相对基址寻址:MOVQ -8(%rbx), -8(%rbx)。要查看是否支持寻址模式的组合,您需要阅读手册的相关说明。

2)

IMUL 指令稍有不同:它把%rax的值乘以操作数,把结果的低64位存在%rax,高64位放在%rdx (两个64位值相乘的结果是128位)。IDIV则相反,把128bit值(低64位在 %rax ,高64位在%rdx)除以指令中的操作数(为了正确处理负数,用CDQO 指令把%rax符号扩展到%rdx),商存储在%rax,余数在%rdx。

PUSH 指令首先减少 ESP 的值,再将源操作数复制到堆栈

3)

JMP指令需要编译器生成目标标签(LABEL)。标签必须唯一,并且是汇编文件内部私有,对外部不可见,除非有.globl指示。按C语言的说法,汇编中没有修饰的标签是static的,.globl修饰的标签是extern的。

4)

栈是一个辅助的数据结构,主要用来记录函数的调用历史和相关的局部变量(没有放到寄存器的)。一般栈是从高地址到低地址向下生长的。%rsp是栈指针,指向栈最底部(其实是平常所说的栈顶)元素。所以,push %rax(8字节),会把%rsp减去8,并把%rax写到 %rsp指向的位置。

SUBQ $8, %rsp
MOVQ %rax, (%rsp)

pop则刚好相反:(这个确实有道理,要理清楚输入输出才行)

MOVQ (%rsp), %rax
ADDQ $8, %rsp

要丢弃最后压入栈中的值,只需要修改%rsp的值即可:

ADDQ $8, %rsp

当然,由于压栈和出栈非常常见,所以这两个操作有两个专有指令,他们的行为和上面描述的完全相同:

PUSHQ %rax
POPQ  %rax

5)

X86-64的调用方式有些不同,称作System V ABI。整个约定相当复杂,下面是简化版,但对我们来说足够了:

  • 整数参数(包含指针)依次放在%rdi, %rsi, %rdx, %rcx, %r8, 和 %r9 寄存器中。
  • 浮点参数依次放在寄存器%xmm0-%xmm7中。
  • 寄存器不够用时,参数放到栈中。
  • 可变参数函数(比如printf), 寄存器%eax需记录下浮点参数的个数。
  • 被调用的函数可以使用任何寄存器,但它必须保证%rbx, %rbp, %rsp, and %r12-%r15恢复到原来的值(如果它改变了它们的值)。
  • 返回值存储在 %eax中.

具体是不是这样还不知道。

6)

上面例子都有很多方式进行优化。比如,特定的代码不使用 %rbx-%r15的时候,就不需要保存。可以把参数保留在寄存器中,而不是压栈。返回值可以直接使用%eax计算,而不是保存到局部变量。手工写代码时,完成这些优化很容易,但是对编译器来说就不这么简单了。

摘录自:深入浅出GNU X86-64 汇编 - 二狗啸地 - 博客园

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值