程序编码

在编译时指定'-Og'选项让GCC产生符合原始程序结构的机器代码

机器级代码

对C语言隐藏, 但对汇编代码可见的:

  • 程序计数器
  • 整数寄存器文件
  • 条件码寄存器
  • 向量寄存器

输出c源码的机器表示

gcc -Og -S mstore.c

机器代码与反汇编的特性:

  • x86-64的指令长度从1-15字节不等
  • 指令设计的格式, 从某个给定位置, 能将字节唯一解码成机器指令

    哈夫曼编码

  • 反汇编无需访问源代码

  • 反汇编与gcc的命名规则有些许差别

    比如movq的q在反汇编中会被省略

关于格式的注解

.file    "mstore.c"
    .text
    .globl    mulstore
    .type    mulstore, @function
mulstore:
.LFB0:
    .cfi_startproc
    pushq    %rbx
    .cfi_def_cfa_offset 16
    .cfi_offset 3, -16
    movq    %rdx, %rbx
    call    mult2
    movq    %rax, (%rbx)
    popq    %rbx
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE0:
    .size    mulstore, .-mulstore
    .ident    "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)"
    .section    .note.GNU-stack,"",@progbits

以上是gcc完整生成的.s文件

所有. 开头的是伪指令, 可以忽略

ATT汇编代码格式

.file    "mstore.c"
    .text
    .globl    mulstore
    .type    mulstore, @function
mulstore:
.LFB0:
    .cfi_startproc
    pushq    %rbx
    .cfi_def_cfa_offset 16
    .cfi_offset 3, -16
    movq    %rdx, %rbx
    call    mult2
    movq    %rax, (%rbx)
    popq    %rbx
    .cfi_def_cfa_offset 8
    ret
    .cfi_endproc
.LFE0:
    .size    mulstore, .-mulstore
    .ident    "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)"
    .section    .note.GNU-stack,"",@progbits

数据格式

  • 16位: 字(w)
  • 32位: 双字(l)
  • 64位: 四字(q)

enter image description here

  • moveb: 传送字节
  • movew: 传送字
  • movel: 传送双字
  • moveq: 传送四字

访问信息

x86-64的CPU包含一组16个存储64位的通用目的寄存器

enter image description here

  • 16位操作可以访问2位字节
  • 32位操作可以访问4位字节

...

栈指针(%rsp)

操作数指示符

  • 立即数: 代表常数

    $后面接c语言表示法的整数

  • 寄存器: 表示寄存器里的内容

    r

    a

    用来表示寄存器a 用R[r

    a

    ]表示里面的内容

  • 内存引用: 指定内存地址里的内容 M[地址]

enter image description here

数据传送指令

enter image description here

enter image description here

压入栈和弹出栈数据

. 将四字压入栈
pushq S 

. 将四字弹出栈
popq D

%rsp 是栈指针 %rax是返回值

算术和逻辑操作

enter image description here

加载有效地址

. x= y+x*4
leaq    (%rdi,%rsi,4), %rax

一元和二元操作

. 从%edi中减去%esi
subl    %esi, %edi

移位操作

. 将x左移四位
salq    $4, %rax

特殊的算术操作

enter image description here

控制

条件码

  • CF:进位标志
  • ZF:零标志
  • SF:符号标志
  • OF:溢出标志

enter image description here

读取条件码

enter image description here

跳转指令

enter image description here

用条件控制实现分支控制

cmpq    %rsi, %rdi
        jg      .L4
        movq    %rdi, %rax
        subq    %rsi, %rax
        ret
.L4:
        leaq    (%rdi,%rsi), %rax
        ret

对应的c代码:

if (x > y){
    return x+y;
}else{
    return x-y;
}

用条件传送实现条件分支

分支预测

enter image description here

循环

  • do-while
  • while

    • guarded-do
  • for

switch语句

跳转表

过程

  • 传递控制
  • 传递数据
  • 分配和释放内存

运行时栈

enter image description here

转移控制

保存当前程序地址,将程序计数器设置为新过程地址 返回时读取保存的地址,继续执行

数据传送

  • 传递函数参数的寄存器

enter image description here

栈上的局部存储

寄存器中的局部存储空间

  • 被调用者保存寄存器
  • 调用者保存寄存器

递归过程

数组的分配和访问

基本原则

T A[N]

指针运算

&D [ i ] [ j ] = X

D

L(Ci+j)

定长数组

变长数组

异质的数据结构

都是对地址进行偏移得到的

  • 结构
  • 联合
  • 数据对齐

在机器级程序中将控制与数据结合起来

理解指针

在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值

GDB调试器

UNIX及UNIX-like下的调试工具

内存越界引用和缓冲区溢出

对抗缓冲区溢出攻击

  • 栈随机化
  • 栈破坏检测
  • 限制可执行代码区域

变长帧

浮点代码

%ymm0 ~ %ymm15

浮点传送和转换操作

enter image description here

enter image description here

enter image description here

过程中的浮点代码

使用XMM寄存器来传递浮点参数

浮点运算操作

enter image description here

定义和使用浮点常数

浮点操作不能把立即数作为操作数

编译器必须为所有浮点常量初始化存储空间

在浮点代码中使用位级操作

enter image description here

浮点比较操作

results matching " "

No results matching " "

results matching " "

No results matching " "