汇编在程序分析中的应用P1

本文通过分析汇编代码,揭示了编译型语言如C/C++在运行时的底层机制。对比了ifelse与switch的效率,指出switch在处理大量离散点时更为高效,而ifelse适合复杂条件判断。同时,讨论了++a与a++的区别,前者先加后赋值,后者先赋值后加。通过对汇编的深入理解,能更好地优化代码性能。
摘要由CSDN通过智能技术生成

我在课本上学的汇编是枯燥的,学了不知道干什么 。但其实汇编可以用来分析一些编译型语言的本质 。我们可以通过查看编程语言官方说明文档进行学习,再通过汇编语言彻底理解其机理。
首先要明白,编译型语言→(编译器)→汇编语言→(编译器)→机器语言,我们使用c/c++作为例子来分析。 在vs2010/2017上标注断点后进入反汇编模式,即可查看汇编代码,这里我们在Windows上通过vs查看的是Intel汇编代码,此外xcode也可以查看AT&T汇编代码,Linux和Uinux可以查看另一种汇编代码,总之汇编代码有很多种,但是内核一致。

分析1: ifelse和Switch哪个效率高

由汇编代码可知,ifelse的原理是不断进行compare,然后j跳转。如果传入的值靠后,则需要比较很多次。而switch的原理是先用一些代码计算出传入值对应switch中的那一个case,然后直接跳转到对应的case内执行语句。
这样看来,如果判断大量离散点,使用switch是一个不错的选择,因为不需要一一比较,只有经过计算选一个case即可。但是如果要判断连续区间或者复杂条件,则可以使用ifelse判断。
ps.使用ifelse时我们可以把出现频率高的内容放到前面,先进行判断。 但是,我们前面分析的是连续的离散点用switch比较好,此时我们计算出各个case语句的地址然后跳转过去即可,例如1.2.3.4.5…。
case1 地址1
case2 地址2
case3 地址3…
default 地址n
(这些case是连续储存的,其地址其实存放在另一块内存,我们使用jmp [address]实现跳转到一个地址里存放的另一个地址,jmp address则是直接跳转到这个地址。)
(在实现最终跳转case的jmp之前还有一个比较cmp已经ja跳转,就是计算一下我们输入的值减去最小的值以后的那个数,有没有我们最大case减最小case那个数大,如果大,则直接通过ja跳转到default,无需接下来的选择)
如果是有间隔的离散点呢?离散点的间隔大小对switch的底层实现有没有影响呢? 当间隔小点离散点例如1.3.6.9…时,编译器底层会会把间隙的地址中放入default情况。
case1 1
default a 2
default 3
case3 4
default 5…
如果间隔很大,编译器就不会这么优化了,因为每次在一个间隔插入一个default就会占用4个字节的内存,我们在牺牲内存减少时间。
间隔很大时我们开辟了一个新的空间:
case从最小到最大连续时有多少个离散点就开辟多少空间,每个空间内存放一个字节。这些空间地址与case值一一对应,如果case是我们给出的则正常编号如00/01/02/03…,把正常的case编好号以后剩余的都赋值一个相同的、比正常编号最后一位多1点编号。
拿到这个编号,再做先前的运算,就能确保正常的case与其对应的语句一一对应,没有写出的case情况都跳转的default。
这种方法把原先增加一个default消耗4B优化为增加一个default消耗1B。
当case的间隔再大呢?这时编译器就自动将其转换为ifelse比较-跳转模式。当case个数较少时编译器也会转换switch为ifelse方式。

分析2: a++和++a

其实++a就是把a赋值给一个寄存器,对寄存器操作做其他运算,最后再把a放到寄存器然后实现把a加一。a++就是把a赋值给一个寄存器,然后实现把a加一,然后再把a赋值给一个寄存器,对寄存器操作做其他运算。
本质区别就是什么时候把a的值赋给寄存器,对寄存器操作做其他运算。

带图笔记:
汇编分析解释型语言重点语法.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值