程序机械级表示——数据格式与访问信息

程序机械级表示——数据格式与访问信息

数据格式

8位称为字节(byte),16位称为字(word),32位为双字(double words),64位为四字(quad words)

C语言基本数据类型对应的x86-64表示如下

C声明 Intel数据类型 汇编代码后缀 大小(byte)
char 字节 b 1
short w 2
int 双字 l 4
long 四字 q 8
char * 四字 q 8
float 单精度 s 4
double 双精度 l 8

大多数GCC生成的汇编代码指令都有一个字符的后缀,表明操作数的大小。例如movb、mobw等等。l后缀可同时表示双字和双精度,因为浮点数使用的是一组完全不同的指令和寄存器,因此不会产生歧义。

访问信息

寄存器

一个x86-64的CPU包含一组16个存储64位值的通用寄存器,用于存储整数和指针。初始的8086有8个16位的寄存器,如下标的%ax到%sp。扩展到IA32架构时,这些寄存器也扩展到了32位寄存器,从%eax到%esp。

63 31 15 7  
%rax %eax %ax %al 返回值
%rbx %ebx %bx %bl 被调用者保存
%rcx %ecx %cx %cl 参数4
%rdx %edx %dx %dl 参数3
%rsi %esi %si %sil 参数2
%rdi %edi %di %dil 参数1
%rbp %ebp %bp %bpl 被调用者保存
%rsp %esp %sp %spl 栈指针
%r8 %r8d %r8w %r8b 参数5
%r9 %r9d %r9w %r9b 参数6
%r10 %r10d %r10w %r10b 调用者保存
%r11 %r11d %r11w %r11b 调用者保存
%r12 %r12d %r12w %r12b 被调用者保存
%r13 %r13d %r13w %r13b 被调用者保存
%r14 %r14d %r14w %r14b 被调用者保存
%r15 %r15d %r15w %r15b 被调用者保存

指令可以通过上表中嵌套的寄存器表示对这十六个寄存器的低位字节进行操作。复制和生成1字节、2字节、4字节、8字节值。当以这些寄存器作为目标时,有这样的规则:生成1字节和2字节数时保持高位剩下的字节不变,生成四字节数时会把高位四字节置为0。

寻址

操作数的寻址可以分为三种类型——立即数、寄存器和内存引用。如下表所示

类型 格式 操作数值 名称
立即数 $Imm Imm 立即数寻址
寄存器 ra R[ra] 寄存器寻址
存储器 Imm M[Imm] 绝对寻址
存储器 (ra) M[R[ra]] 间接寻址
存储器 Imm(rb) M[Imm + R[rb]] 基址寻址
存储器 (rb, ri) M[R[ra] + R[rb]] 变址寻址
存储器 Imm(rb, ri) M[Imm + R[ra] + R[ri]] 变址寻址
存储器 (, ri, s) M[R[ri] * s] 比例变址寻址
存储器 Imm(, ri, s) M[Imm + R[ri] * s] 比例变址寻址
存储器 (rb, ri, s) M[R[rb] + R[ri] * s] 比例变址寻址
存储器 Imm(rb, ri, s) M[Imm + R[rb] + R[ri] * s] 比例变址寻址

数据传送

最简单的数据传送指令是MOV类,movb、movw、movl、movq这四条指令执行相同的操作,不同的是他们的操作数的大小不同

指令 效果 描述
MOV S, D D<—S 传送
movb   传送字节
movw   传送字
movl   传送双字
movq   传送四字
movabsq I, R R<—I 传送绝对的四字

源操作数指定的值是一个立即数,存储在寄存器或者内存中。目的操作数指定一个位置,要么是一个寄存器,要么是一个内存地址。x86-64增加了一条限制,两个操作数不能都指向内存位置,要将一个值从内存中的一个位置复制到另一个位置必须先将源值加载到寄存器,然后再写入目的内存地址。

常规的movq指令只能以表示为32位补码数字的立即数作为源操作数,然后把该值符号扩充得到64位的值并放到目标位置。movabsq指令能够以任意64位立即数作为源操作数,并且只能以寄存器作为目的。

在将较小的源值复制到较大的目的地时使用movz或者movs指令。

MOVZ类中的指令把剩余的字节填充为0,MOVS则填充为源操作数的最高位。两种指令格式为mov[z/s + 后缀1 + 后缀2],即第一个后缀为源操作数的大小,第二个后缀为目的地址的大小。

MOVS类中还给出了cltq指令。cltq指令没有操作数,他总以寄存器%eax作为源,%rax作为符号扩展结果的目的,也就是等效于movslq %eax, %rax,不过编码更紧凑。

数据传送实例

C语言代码如下

long swap(long *des, long src)
 {
     long tmp = *des;
     *des = src;
     return tmp;
 }

产生的汇编代码如下,%rdi为参数一即des,%rsi为参数二src,%rax为返回值

swap:
  movq (%rdi), %rax
  movq %rsi, (%rdi)
  ret

上面的汇编代码将%rdi中的指针des作为地址在内存中寻址,并将des指针指向的值传输到返回值%rax中即tmp。由于long类型为4字,因此使用movq。第三行同理,将%rsi寄存器中的值直接传输到%rdi寄存器中的指针des指向的内存地址,最后返回结果。

------本页内容已结束,喜欢请分享------

文章作者
能不能吃完饭再说
隐私政策
PrivacyPolicy
用户协议
UseGenerator
许可协议
NC-SA 4.0


© 版权声明
THE END
喜欢就支持一下吧
点赞25赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片