汇编语言特殊算数操作

汇编语言特殊算数操作


首先纠错

image-20220407195514558

书上除法这里是有错误的,商和余数都放在了R[%rdx]这显然是不合理的,我觉得应该写为:

image-20220407210130248

乘法

c源文件

#include <inttypes.h>
typedef unsigned __int128 uint128_t;
//此处改名的目的是让128位整数能够类似64位整数使用
void store_uprod(uint128_t *dest,uint64_t x,uint64_t y){
                *dest=x*(uint128_t) y;
}

汇编语言

        movq    %rsi, %rax
        mulq    %rdx
        movq    %rax, (%rdi)
        movq    %rdx, 8(%rdi)
        ret

逻辑分析:

首先三个参数分别存放在

在这里插入图片描述

R[%rdi]=dest//这里%rdi寄存器中存放的是dest这个位置 dest这个位置 dest这个位置
R[%rsi]=x
R[%rdx]=y

1.movq %rsi, %rax

即令R[%rax]=R[%rsi]=x将x放在了%rax寄存器中

2. mulq %rdx

R[%rdx]=y

image-20220407195537665

看似只有一个操作数,实际上隐含着另一个操作数在%rax寄存器中

即令R[%rdx]*R[%rax],两个64位数的计算机结果是一个128位数,显然单独一个64位寄存器是放不下的,因此计算结果被分成两部分

低64位放在%rax寄存器,高64位放在%rdx寄存器

3. movq %rax, (%rdi)

R[%rdi]=dest这是指针指向内存中的位置

M[R[%rdi]]=M[dest]对内存中的位置dest应用解引用函数 M [ d e s t ] M[dest] M[dest]得到的是该地址上的实际数值

M[R[%rdi]]=R[%rax],将%rax寄存器中刚刚算出的低64位结果放在内存中,位置为R[%rdi](间接寻址)

4. movq %rdx, 8(%rdi)

刚才在第3步时存放了低64位,那么此时应该做到就是存放高64位

M[R(%rdi)+8]=R[%rdx],将%rdx寄存器中刚刚算出的高64位结果放在内存中,位置为R(%rdi)+8(基址+偏移量寻址)

此处的+8为偏移8个字节,因为低地址恰好占用这8个字节

在小端机器上低地址存放低位,高地址存放高位

到此乘法的计算结果已经被分成两个64位数存进了一个uint128_t *指针指向的地址

除法

c源文件

void remdiv(long x,long y,long *qp,long *rp){//希望计算x/y将商存到指针qp指向的地址,将余数存到指针rp指向的地址
        long q=x/y;
        long r=x%y;
        *qp=q;
        *rp=r;
}

汇编语言

        movq    %rdi, %rax
        movq    %rdx, %r8
        cqto
        idivq   %rsi
        movq    %rax, (%r8)
        movq    %rdx, (%rcx)
        ret

在这里插入图片描述

R[%rdi]=x
R[%rsi]=y
R[%rdx]=qp
R[%rcx]=rp

1. movq %rdi, %rax

R[%rax]=R[%rdi]=x将x存放在%rax寄存器里

2. movq %rdx, %r8

R[%r8]=R[%rdx]=qp将商在内存中的地址存放在%r8寄存器里

在这里插入图片描述

对于一个128位数的除法运算,被除数的低64位存放在%rax寄存器中,高64位存放在%rdx寄存器中

刚才在第1步时已经将64位数x放在%rax寄存器中了,但是高64位所在的%rdx现在被第三个参数qp占用,因此将qp放在另一个寄存器%r8中,然后将%rdx腾出来方便存放高64位

3. cqto

在这里插入图片描述

为什么要进行符号拓展?

被除数应该是一个128位数,但是目前我们只是确定了其低64位为x,高64位还是第三个参数的值没有修改,如果此时直接计算则高64位的值可以认为是乱码,那么怎么消除高64位的乱码呢?置零或者置符号,我们将要进行符号除法,因此高64位置符号

即高64位按照R[%rax]=x的符号位拓展

4. idivq %rsi

R[%rsi]=y

在这里插入图片描述

R[%rdx]=x mod y

R[%rax]=x/y

5. movq %rax, (%r8)

R[%r8]=qp

M[R[%r8]]=M[qp]=*qp=R[%rax]=x/y

6.movq %rdx, (%rcx)

R[%rcx]=rp

M[R[%rcx]]=M[rp]=*rp=R[%rdx]=x mod y

习题3.12

在这里插入图片描述

首先四个参数的存放位置为:

image-20220407201308477

执行除法的时候只会提供一个操作数S作为除数,表示被除数的另两个操作数是隐含的%rax,%rdx

image-20220407210829932

那么在执行除法命令之前,应该把被除数先安置好

1.首先128位被除数的低64位存放在%rax中,即R[%rax]=x
2.然后高64位存放在%rdx中,无符号除法时应当全置0,

但是由于第三个参数qp已经占据了%rdx,因此在将其全都置零之前应当请三个参数挪个地方,比如%r8

movq %rdx,%r8

3.此时就可以将被除数的高64位%rdx寄存器置0了,最直接的置零方法是movq $0,%rdx,还可以利用异或的性质xorq %rdx,%rdx

至于应该选择哪一个?应该选择二进制长度最短的指令

0000000000000000 <.text>:
   0:   48 c7 c2 00 00 00 00    mov    $0x0,%rdx
   7:   48 99                   cqto
   9:   48 31 d2                xor    %rdx,%rdx

由此可见为什么刚才有符号除法时要用cqto,因为其长度最短

然后xor也是不错的选择

最迫不得已才会选择movq指令

当发现实际编译器使用的命令与我们理想的不一样时,可以写一个.s文件然后将自己理想的汇编指令和实际的汇编指令各写一行

然后使用gcc -Og -c 命令,使其编译成为.o文件,注意必须指定-c选项,否则直接编译成.exe或者.out会发生链接错误,因为刚才我门写的.s文件是非常不完整的,连main函数都没有

然后对.o文件使用objdump命令反编译 ,就可以观察指令及其二进制编码长度了

一般理想与现实不同都是由于有更加短但是可以完成同样目的的指令我们没有考虑到

在本题中我不知道类似cqto但是是无符号拓展的指令,可以先用异或指令达到相同的目的

4.被除数在3中已经准备好了,可以进行除法了
在这里插入图片描述

这里S是除数,本题中除数是第二个参数y存放在%rsi寄存器中,即R[%rsi]=y

那么除法指令为divq %rsi

5.除法进行完毕,瓜分商和余数

商位于%rax寄存器中,希望传送到内存中的qp位置,而内存中的qp位置存放在寄存器%r8中(即R[%r8]=qp,M[R[%r8]]=*qp)因此使用指令movq %rax,(%r8)

余数位于%rdx寄存器中,希望传送到内存中的rp位置,而内存中的rp位置存放在寄存器%rcx中(即R[%rcx]=rp,M[R[%rcx]]=*rp)因此使用指令movq %rdx,(%rcx)

外链图片转存失败的臭毛病能不能改啊,非得手动一张张上传

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰球球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值