第三章、汇编2

算术逻辑操作

加载有效地址

leaq 这个指令是烦人的,leaq (address), %rax, 首先(address)表示获取某个地址的值,而leaq(load effective address)又是去取得一个值的地址(&value),那么取得的结果就是address, 所以本质就是把address放到寄存器中。这个好处是可以利用一些简单的加法和乘法,减少指令个数。可以做一下书里的练习题。

一元和二元操作

  • inc
  • dec
  • neg
  • not

移位操作

  • sal k,D 代表左移,D=D<<k
  • shl k,D
  • sar k,D 算术右移,补上符号位
  • shr k,D 逻辑右移 ,补零
    对于C/C++代码,都是算术右移,这个要注意

特殊算术操作

乘法

有符号乘法和无符号乘法有两种,一种是64bit64bit=64bit, 还有是64bit64bit=128bit, 这种对寄存器的使用有特殊要求,两条指令虽然名字一样但操作数不一样(类似于jmp),汇编器会根据指令的操作数个数来翻译对应的二进制。

  • imulq S
  • imulq A, B
除法

除法和乘法差不多,不过只有一个操作数,分子是128bit,分母是64bit。然后也是一堆寄存器倒腾。

控制

条件码

条件码是cpu中的一个寄存器,可以理解为32bit, 每一个bit代表标志符,目前只用了几个,剩下的是保留位。

  • 各种alu单元做完计算后会自动更新对应的标识符。leaq 指令不会触发条件变化,我理解这玩意在汇编器时候就算好了,没有在运行时计算。
  • 还有一类指令只设置条件码,其他啥事不干。具体如下:
    cmpb/w/l/q A ,B 会根据(B-A)的结果设置标志符
    testb/w/l/q A,B

访问条件码

条件码一般不会被直接访问,目前主要有三种方式:

  • set指令 A(这个指令会观测eflags的几个标识符组合,如果符合要求的话就把A设置为0 or 1, 一般目的A是一个8位寄存器比如al或者是一个8bit的内存),注意这个玩意一般和cmq配合使用,不然你每次想用的时候去查标识符组合,心态会查爆炸。
  • 跳转指令
    这里有个疑惑记录一下,140页书里有一行代码:7f f8 // jg 5
    跳转指令相对位置编码很好理解,但是书里把0xf8翻译成-8我就很不理解,

问:为啥反汇编的话这么确定就把这个二进制当作补码处理来翻译?
查阅资料有人说汇编后的二进制数都是补码,这个姑且先这么看,权威资料没查到。
问:如果0xf8被翻译成-8,那么248这个数值二进制咋表示?
chat-gpt解释如下:其实jmp分为相对短跳转(short jump)和相对长跳转(near jump),二者的汇编虽然都是用jmp这三个字母,但是汇编器会根据输入立即数的大小翻译成不同的二进制, 指令分别被翻译EB(短跳转) 和 E9(长跳转), 二者立即数范围分别是1字节(-128~+127)和4字节 (-2,147,483,648 ~ +2,147,483,647)。举个例子:

  1. jmp $4096 最后会被汇编器翻译成:
    E9 00 00 10 00(小端机器)
  2. jmp $-8 最后会被汇编器翻译成:
    EB f8
  3. jmp $248 最后会被汇编器翻译成:
    E9 f8 00 00 00 (小端机器)

除了jmp这个指令外,其他的跳转指令是根据条件码的某种组合决定是否跳转,所以也算是访问到eflags一种方式。

这里讲解一下跳转指令编码,写汇编代码的时候可以直接写jmp .L2这种,但是后面汇编器和链接器都会对这个跳转目标进行修改。汇编器一般会利用相对位置编码,把目标地址和jmp指令的下一条地址的差作为目标,当链接参与的时候,一般会把这些相对位置调整为具体的绝对地址。

用条件控制来实现条件分支

很简单,对条件进行判读,条件符合走A分支,不符合就走B分支

用条件传送来实现条件分支

很简单,同时把A和B分支两个结果都算出来,然后再根据条件选择一个正确的结果,这种策略叫做数据的条件转移,会用到条件移动指令cmov,不过使用场景苛刻但是效率高(原因的话在后面一章会介绍,这里简单解释一下)。

处理器都是通过pipeline来获取高性能,一条指令会被切分为很多小单元,比如上一条指令A在计算时候,下一条B指令可以做取指令的操作也不会影响到A.要做到这一点需要事先确定执行的指令序列这样才能保证pipeline中充满待执行的指令。尽管intel这些cpu有很牛逼的预测机制,但也只有90%的概率猜中分支路径,一旦猜错了,那么把pipeline的任务全部清空重新填充流水线,大约浪费15-30个周期。所以如果分支判断时间严重高于运算时间,切分支判断随机性很强的话,条件分支的代码就会很差。gcc只有在分支中极端简单时候才会按照条件传送编译,否则还是按着常规的分支控制来实现分支。

条件移动指令cmov A,B: 根据eflags中的某些组合达标才会进行A寄存器到B寄存器的数据搬移。

循环

虽然c语言中有do-while, while, for三种循环方式,但是实际编译器只有两种:
*do-while

*guarded-do

switch语句

利用查表方式进行跳转,没啥可说的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值