程序编码

汇编代码

  • 汇编代码是人类可读的机器代码。
  • 机器代码是一堆字节序列,它是对一系列指令的编码。
  • 对下列代码使用 gcc -Og -o prog main.c mstore.c 生成可执行文件。使用gcc -Og -S mstore.c 可以生成汇编文件。 ```c

    include

void multstore(long, long, long *);

int main(){ long d; multstore(2,3,&d); printf(“2 * 3 —-> %ld\n”,d); return 0; }

long mult2(long a, long b){ long s = a*b; return s; }

  1. ```c
  2. #include <stdio.h>
  3. #include <string.h>
  4. long mult2(long, long);
  5. void multstore(long x, long y, long *dest){
  6. long t = mult2(x,y);
  7. *dest = t;
  8. }
  • 对prog 可执行文件使用objdump反汇编器,可以找到机器代码和汇编代码的对应关系

    寄存器与数据传送指令

    寄存器

  • 每个寄存器都有自己特殊的功能,早期的寄存器是16位的,随着处理器架构的发展,一直升级到现在的64位寄存器。

  • image.png

    指令

  • 指令可以分解为:操作码 操作数

    1. 操作码 操作数
    2. pushq %rbp
    3. movq %rsp, %rbp
    4. pushq %rbx
    5. pushq %rax
    6. movq %rdx, %rbx
    7. callq _mult2
    8. movq %rax, (%rbx)
    9. addq $8, %rsp
    10. popq %rbx
    11. popq %rbp
    12. retq
  • 操作数可以是一个立即数,寄存器,或者内存引用。以‘$’开头的代码是一个立即数,用来表示一个参数。寄存器表示某个寄存器里面的内容,比如%rbp,%rsp。内存引用表示某个计算出来的地址,比如(%rbx)。

  • 内存引用的地址计算方法第三章 程序的机器级表示 - 图2 = 第三章 程序的机器级表示 - 图3

    • rb: 基址寄存器
    • ri:变址寄存器
    • Imm:常数
    • s:比例因子(1,2,4,8)

      MOV指令

  • MOV指令由一个源操作数和一个目的操作数构成,MOV指令负责将数据从一个位置复制到另一个位置。

  • 源操作数:可以是立即数,寄存器,或者内存引用。
  • 目的操作数:只能是寄存器或者内存引用。 ```c
    1. 源操作数 目的操作数
    movq %rsp, %rbp pushq %rbx pushq %rax movq %rdx, %rbx
  1. <a name="j3aiz"></a>
  2. ## 压入和弹出数据栈
  3. - **pushq S/popq D** 可以实现数据的压入和弹出。
  4. - pushq %rbp 等价于
  5. ```c
  6. subq %8, %rsp//先减去8个字节,0x108变更为0x100
  7. movq %rbp,(%rsp)//把数据压入到0x100的位置
  • popq %rax 等价于

    1. movq (%rsp),%rax //移动栈顶的元素到rax中。
    2. addq %8,%rsp //栈顶地址+8字节 恢复0x108
  • image.png

  • 无论如何,%rsp总是指向栈顶,数据总是从栈顶开始操作的。执行push,rsp地址变小。执行pop,rep地址变大。

    算术和逻辑操作