程序的机器级表示

操作数: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存放在%rsi
leaq      (%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*z
salq  $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)
    Body

Init;
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                    # 返回
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值