• 细说align 的作用及用法


    .align 就是用来对齐的,究竟怎么对齐,有啥情况?下面分析一下

    基本情况讲解

    (一)

    $vim align1.s

    在新建的文件编辑以下代码:

    1
    2
    3
    4
    5
    6
    _start:
    b reset
    .byte 0x55
    .byte 0xaa
    reset:
    ldr r0, =0x53000000

    保存后,执行如下命令:

    1
    $arm-linux-as align1.s -o align1.o

    这样的话有的编译器可能会报错,但我的编译器没有报错,虽然没有报错,但反汇编的结果显示,运行时肯定会出问题。

    执行如下命令(进行反汇编):

    1
    $arm-linux-objdump -d align1.o

    显示如下:

    1
    2
    3
    4
    5
    00000000 <_start>:
    0: ea000000  b  4  <_start+0x4>
    4: 0453aa55  ldreqb s1, [r3], -#2645
    00000006 <reset>:
    6: e3a00453  mov r0, #1392508928 ; 0x53000000

    很明显,跳转语句应该跳到0x06处,而它却跳到0x04处,我们分析一下。首先,ARM指令都是32位的,这里要求4字节(一个word)对 齐,b reset 指令占了4个字节,接着我们用 .byte 指令定义2个常数,因为这里是 byte 类型,所以只占了八位,两个数据,一共占16位。由于连接器内部有一个程序地址计数指针,里面保存着当前的地址,这地址指针是连接器内部工作需要的,我们 不需要理会,只需要了解有这么一个机制。假如_start从0x00,第一条指令占4个byte,然后连续分配2个byte,当前地址指针应该是 0x06,那么问题来了,下条指令,也就是标号 reset 处的ldr指令,是一条ARM指令,这要求是 4个字节对齐的,当前的地址为 0x06,并不能满足这个要求,所以编译器自动将地址指针跳到0x04。

     

    解决办法很简单,我们只需要加一条 .align 指令,问题就解决了

    1
    2
    3
    4
    5
    6
    7
    _start:
    b reset
    .byte 0x55
    .byte 0xaa
    .align
    reset:
    ldr r0, =0x53000000

    编译结果是:

    1
    2
    3
    4
    5
    00000000 <_start>:
    0: ea000000  b 8 <reset>
    4: 0000aa55  andeq sl, r0, r5, asr sl
    00000008 <reset>:
    8: e3a00453  mov r0, #1392508928 ; 0x53000000

    在两个 .byte 指令后自动补零,直到满足地址要求为止。这里就是将地址累加到 0x08符合ARM指令要求,所以在这里写入下条指令。

    这是基本内容,下面研究一下其他情况

    (二).align 5

    这里只是一个例子,重点想说的是 这个 .align 5 后面的 5 究竟是什么意思? uboot里面就有这指令。我们继续做做试验,看看编译结果是什么

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    _start:
    b reset
     
    .align 5
    .byte 0x55
     
    .align 5
    .byte 0xaa
     
    .align
    reset:
    ldr r0, =0x53000000

    编译结果:

    1
    2
    3
    4
    5
    6
    7
    8
    00000000 <_start>:
    0: ea00000f  b 44 <reset>
    ...
    20: 00000055  andeq r0, r0, r5, asr r0
    ...
    40: 000000aa  andeq r0, r0, sl, lsr #1
    00000044 <reset>:
    44: e3a00453  mov r0, #1392508928 ; 0x53000000

    我们发现这编译结果有点意思,这地址分配一下子上去了,但是也不难,分析一下就OK,看那个 20 和 40 ,这里是十六进制,也就是 32 和 64了。那么很容易可以联想到,这里做的是幂运算,也就是 .align 5 对齐的地址为 2^5 = 32,之前的地址全部补零。

    (三).balignl 16,0xdeadbeef

    1
    2
    3
    4
    5
    6
    7
    _start:
    b reset
     
    .balignl 16,0xdeadbeef
     
    reset:
    ldr r0, =0x53000000

    在看uboot的时候还有这么一个语句,查了半天as的手册才找到,囧,不过稍微做了一下实现,觉得又不是很难,我们看看结果:

    1
    2
    3
    4
    5
    6
    7
    00000000 <_start>:
    0: ea000002  b 10 <reset>
    4: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}
    8: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}
    c: deadbeef  cdple 14, 10, cr11, cr13, cr15, {7}
    00000010 <reset>:
    10: e3a00453  mov r0, #1392508928 ; 0x53000000

    可以看出,这指令就是将 deadbeef字符串填进去,一共填到地址为16对齐的地方为指,上面可以看到,这里填到 0x10 也就是 16了。

  • 相关阅读:
    server.Execute 执行子请求时出错
    mybatis逆向工程
    上传及下载github项目
    基于tess4j的图片文字提取
    myeclipse中更改默认jdk版本出错( Target is not a JDK root. System library was not found)
    SSM整合环境搭建demo
    AMD CPU环境下使用android studio,eclipse的Genymotion插件
    Android Studio电脑不支持HAXM的解决办法
    完整使用JDBC访问数据库
    springMVC保存数据到mysql数据库中文乱码问题解决方法
  • 原文地址:https://www.cnblogs.com/Ph-one/p/6424270.html
Copyright © 2020-2023  润新知