程序的机器级表示

来源:互联网 发布:员工信息管理java 编辑:程序博客网 时间:2024/05/17 23:37

操作数:CP121

  • 立即数(Imm):

    • 以$开头
    • 立即数寻址
  • 寄存器值(Reg):

    • 16位寄存器的低1字节,2字节,4字节或8字节。
    • ra表示寄存器a,R[ra]表示寄存器的值
    • 寄存器寻址
  • 内存引用(Mem)
    • 根据计算出的地址来访问某个内存位置
    • Mb[Addr]表示存储在以地址开始b个字节的引用

MOV类指令

  1. 将数据从一个位置复制到另一个位置
  2. 第1个是源操作数,第2个是目的操作数
  3. 2个操作数不能都指向内存

示例

long exchange(long *xp,long y){   long x=*xp;   *xp=y;   return x;}
//开始时xp存放在%rdi(存放目标索引值)//y存放在%rsi(存放源索引值)exchange:   //寄存器间接寻址   movq    (%rdi),%rax   //由于xp是指针,所以%rdi存放的是地址。将位于该内存地址的值复制到%rax(局部变量通常存在寄存器中)   movq    %rsi,(%rdi)   //将y的值复制到%rax的内存地址   ret    //返回

CP129
加载有效地址指令:
将源操作数的地址写入目的操作数(必须是寄存器)

long t=x+4y;//假设x存放在%rdiy存放在%rsileaq      (%rdi,%rsi,4),%rax//将%rax的值设为x+4y

一元操作:操作数可以是寄存器/内存地址
二元操作:

  1. 第一操作数:立即数/寄存器/内存地址
  2. 第二操作数:寄存器/内存地址(读出后写回)

比较指令:CP136

CMP S1,S2//基于S2-S1

示例:

long arith(long x,long y){   long t1=x^y;   long t2=x*48   return t2;}
xorq  %rsi,%rdi//结果存在%edi(第一个参数)leaq  (%rsi,%rsi,2),%rax//3*zsalq  $4,%rax//左移4位,每移1次相当于乘2

跳转指令
无条件跳转:

//直接跳转jmp  .L1//跳转到L1//间接跳转jmp  *(%rax)//%rax存储的是

条件分支:

  • 条件控制:CPU 依靠流水线工作的,比方说执行一系列操作需要 ABCDE 五个步骤。执行 B 所需的数据会在执行 A 的同时加载到寄存器中,如果程序一直是顺序的,效率会很高。
    一旦遇到分支,执行完 A 下一步要执行的是 C,但是载入的数据是 B,这时候就要把流水线清空,然后重新载入 C 所需要的数据。『分支预测』这一技术来解决(分支预测有概率可能猜错)。
  • 条件传送:
    • 先计算出表达式的值
    • 只有当表达式的值容易计算时才会采用条件传送
long absdiff(long x, long y){    long result;    if (x > y)        result = x-y;    else        result = y-x;    return result;}

反汇编

long result;    int ntest = x <= y;    if (ntest) goto Else;    result = x-y;    goto Done;Else:    result = y-x;Done:    return result;

汇编

    movq    %rsi, %rax  # x    subq    %rdi, %rax  # result = y-x    movq    %rdi, %rdx    subq    %rsi, %rdx  # eval = y-x    cmpq    %rsi, %rdi  # x:y    cmovge  %rdx, %rax  # %rax存储返回值    ret

循环:

  • 组合条件测试和跳转产生循环的效果
  • do-while
loop:   循环体;   t=循环条件;   if(t)  goto loop;

例如

long pcount_goto(long n){    long result = 1;loop:    result *=n;    n=n-1;    if (n>1) goto loop;    return result;}
pcount_goto:    movl    $1, %eax    # result = 1.L2:                    # loop:    imulq   %rdi, %rax # %rdi=n,%rax=result    subq    $1, %rdi       cmpq    $1, %rdi       jg     .L2         # 大于跳转    rep; ret
  • while
    guarded-do(较高优化等级):初始条件成立时,进入do-while循环( Do-While 语句执行起来更快,更符合 CPU 的运算模型)
t=循环条件;if(!t)    goto done;loop:    循环体;    t=循环条件;    if(t)      goto loop;done:
  • for循环
初始表达式;for (Init; Test; Update)    BodyInit;while (Test) {    Body    Update;}

switch

  • 跳转表

    • 是1个数组
    • 数组元素为代码段,开关索引值等于某个i时进行跳转
    • 开关数量比较多且值的跨度比较小时使用

    CP160 void* jt[7]是跳转表,元素(例如&&loc_A)代表代码段的地址。为了使下标从尽可能小的地方开始,将n-100作为开关索引值。

过程:
图3-25
对于每个过程调用来说,都会在栈中分配一个帧 Frames。每一帧里需要包含:返回信息,本地存储(如果需要)临时空间

  • 传递控制:调用时将PC设置成被调用函数的起始地址;返回时将PC设置成原函数的下1条指令。
  • 传递数据:

    • 参数:不超过6个通过寄存器传递(图3-28)
      这里写图片描述;超过6个通过栈传递
    • 返回值:通过寄存器%rax传递
  • 分配释放内存:CP170局部变量有时需要存放在内存中

long mult2(long a, long b){    long s = a * b;    return s;}//汇编0000000000400550 <mult2>: # a 在 %rdi 中,b 在 %rsi 中    mov     %rdi, %rax      # 得到 a 的值    imul    %rsi, %rax      # a * b # s 在 %rax 中    retq                    # 返回
void multstore (long x, long, y, long *dest){    long t = mult2(x, y);    *dest = t;}0000000000400540 <multstore>:# x 在 %rdi 中,y 在 %rsi 中,dest 在 %rdx 中    push    %rbx            # CP173被调用者保护寄存器    mov     %rdx, %rbx      # 保存 dest# 程序计数器%rip指向mult2的起始地址    callq   400550 <mult2>  # 调用 mult2(x, y)# 返回结果在 %rax 中    mov     %rax, (%rbx)    # 保存到 dest指向的地址    pop     %rbx            # 恢复%rbx的原值    retq                    # 返回
原创粉丝点击