关于ppc的32位立即数加载问题

来源:互联网 发布:软件模块化设计 编辑:程序博客网 时间:2024/05/20 21:43

   在ppc指令体系中,一次最多加载16位立即数。要加载32位立即数,必须分两次进行。很多资料上使用如下加载指令:

    lis r0, 0x1122

    addi r0, r0, 0x3344

    这样做确实可以成功地把0x11223344加载到r0中。可是如果换成0x11118000呢?

    lis r0, 0x1111

    addi r0, r0, 0x8000 

    请注意, addi指令是r0 = r0 + EXTS(0x8000). EXTS(0x8000) = 0xffff8000。如此,加载到r0中的值就不是0x11118000,而是0x11108000。差之毫厘,谬以千里。

    那gcc是如何实现加载32位立即数的指令的呢?

    首先是加载0x11223344的指令, 这是对c代码反汇编得出的指令:

    lis r0, 0x1122

    ori r0, r0, 0x3344

    gcc放弃了addi指令,转而使用ori指令。ori指令是r0 = r0 | (16'0 | 0x8000),加载到r0中的为0x11223344。

    然后是加载0x11118000的指令,自然也是用ori指令:

    lis r0, 0x1111

    ori r0, r0, 0x8000

    所以说,加载32位立即数时要小心,如果其第15位为1,用addi就会加载出错误的数值,还是用ori较为保险

    

    其实,在ppc指令中,加载32位立即数并不是很常见,常见的是需要将一个数从一个32位地址中加载出来,或者将一个数保存到32位地址中。

    我们来看通常的做法,假设是将地址0x11223344中的值加载到r0中:

    lis r1, 0x1122

    lwz r0, 0x3344(r1)

    那如果是将地址0x11118000中的值加载到r0中呢?

    lis r1, 0x1111

    lwz r0, 0x8000(r1)

    不好意思,lwz指令是指r0 = MEM[r1 + EXTS(0x8000)], 所以变成r0加载地址0x11108000处的值。

    至于gcc的做法,自然是先用lis加ori指令将地址存入寄存器中,再读取内存内容。

    但这样并不是说lwz/lhz/lbz等指令就没有用,它们用处很大,这些指令可以进行正负偏移2^15内的寻址。编译器在将高级代码翻译成汇编指令时,已知偏移的大小,可以酌情采用lwz/lhz/lbz等指令,而省去ori指令。除此之外,如果明确知道偏移是正的,也可以直接用lwz来组合地址,比如之前的地址0x11223344。但如果不太明确,保险起见,还是要用ori指令,不然会埋下很深的安全隐患!


 转自:http://blog.csdn.net/qb_2008/article/details/7907398


原创粉丝点击