zoukankan      html  css  js  c++  java
  • 令人迷惑的AT&T的jmp:直接跳转和间接跳转 [转]

    最近看链接器源码中,对位置无关代码PIC(共享库)的链接问题,发现对call和jmp很多不常用的用法,这里试验并总结了一下各种用法。

    我们最常用的jmp形式,就是 jmp后面跟个标签!这个没什么可说的!

    假如标签叫做mylabel,它的地址是0x8048377,而且有个全局变量b,b存储的内容就是mylabel的地址,而b的地址是0x80494A8。
    即有这样的赋值(加载)语句:
    movl$mylabel,%eax//把mylabel的地址加载到eax寄存器中
    movl%eax,b//把mylabel的地址加载到b中
    movl$b,%ebx//把b的地址加载到ebx寄存器中
     
    我们考虑下面的语句:
    1.jmpmylable
    2.jmp0x8048377
    3.jmp%eax
    4.jmp*%eax
    5.jmp*(%ebx)
    6.jmp*0x80494A8
    7.jmp*b
    8.jmp$0x5
     
    这7句jmp语句!分别都做了什么?
     
    1.不用说,跳转到mylabel标签处继续执行代码,但是,是如何跳转的呢?就是PC加上了mylabel标签处对于jmp处的一个偏移地址!可执行的二进制代码是这样表示的:eb 03,就是说,pc+0x03就可以了。
     
    2.这里,0x8048377是mylabel的地址,我以前研究过,标签的作用,更他的地址的作用是等效的。所以,这里的执行效果跟1中的相同。但是,还有些不一样!这里的二进制代码成了:e9 03 00 00 00 这里用了32位表示了这个偏移,而在1中,只用了8位!
     
    3.在编译链接的时候,这句代码会有警告:warning:indirect jmp without '*'。间接跳转没有‘*’符号,但是,执行起来,还是没有错。看一下二进制的可执行文件的代码,发现,给补上了个‘*’号!而且二进制是:ff e0.
     
    4.其实,4是3的补充版,正常的形式就是4,而三是有警告的被补充的版本。
     
    5.%ebx是b的地址,那么(%ebx)表示ebx的值为地址,指向的地方。这里指向了b的内容,也就是mylabel的地址!于是,化简后,5也就等效与2,但是,二进制表示是:ff 23。
     
    6.0x80494A8是b的地址,这里看做内存数,那么实质上,b指向的值是mylabel的地址,于是,化简后同2,二进制代码是:ff 25 a8 94 04 08。
     
    7.b是标签,代表一个地址,所以,这里同6,二进制代码也同6
     
    8.这句话是错误的,jmp不支持立即数!
     
    所以说,正确的写法有:
     
    1.jmpmylable//eb 03
    2.jmp0x8048377//e9 03 00 00 00
     
    3.jmp*%eax//ff e0
    4.jmp*(%ebx)//ff 23
    5.jmp*0x80494A8//ff 25 a8 94 04 08
    6.jmp*b//ff 25 a8 94 04 08
     
    1和2叫做间接寻址,就是算偏移量的。后面没有‘*’号,而是直接一个标签或者地址(标签就可以看做是地址),所以说,就是一个直接的地址的值。间接跳转的二进制代码是eb或者e9,是e开头的。
    3,4,5,6叫做直接寻址,直接寻址的标识就是这个‘*’号!直接寻址,就是PC直接赋值某个地址,而不是加偏移量。所以,‘*’号后面的部分,其实是一个要付给PC的值,那么,取值的方式就好想象了!直接跳转的二进制代码是ff开头的。
     
    3是寄存器直接取值;4是寄存器间接取值;5是内存数取值;6是标签取值(实质上同5)。
     
    确实,有点意思~
    call同jmp指令!
     
  • 相关阅读:
    第三周学习进度条
    软件工程个人作业02
    构建之法阅读笔记02
    学习进度条
    构建之法阅读笔记01
    软件工程个人作业01
    构建之法粗读
    第一次作业
    动手动脑接口与继承
    大道至简第七章第八章
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2798101.html
Copyright © 2011-2022 走看看