0

比较来自两个不同制造商的两个 Thumb-2 micros。一个是 Cortex M3,一个是 A5。他们是否保证将特定的代码段编译为相同的代码大小?

4

1 回答 1

0

所以这里

乐趣.c

unsigned int fun ( unsigned int x )
{
    return(x);
}

addimm.c

extern unsigned int fun ( unsigned int );
unsigned int addimm ( unsigned int x )
{
    return(fun(x)+0x123);
}

出于演示目的,为裸机构建,并不是一个真正的功能程序,但它编译干净并演示了我打算演示的内容。

手臂指令

arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-a5 -march=armv7-a -c addimm.c -o addimma.o

对象的反汇编,未链接

00000000 <addimm>:
   0:   e92d4008    push    {r3, lr}
   4:   ebfffffe    bl  0 <fun>
   8:   e2800e12    add r0, r0, #288    ; 0x120
   c:   e2800003    add r0, r0, #3
  10:   e8bd8008    pop {r3, pc}

thumb 通用(armv4 或 v5,无论此编译器构建的默认值是什么)

arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -c addimm.c -o addimmt.o

00000000 <addimm>:
   0:   b508        push    {r3, lr}
   2:   f7ff fffe   bl  0 <fun>
   6:   3024        adds    r0, #36 ; 0x24
   8:   30ff        adds    r0, #255    ; 0xff
   a:   bc08        pop {r3}
   c:   bc02        pop {r1}
   e:   4708        bx  r1

皮质-a5 特异性

arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -mcpu=cortex-a5 -march=armv7-a -c addimm.c -o addimma5.o

00000000 <addimm>:
   0:   b508        push    {r3, lr}
   2:   f7ff fffe   bl  0 <fun>
   6:   f200 1023   addw    r0, r0, #291    ; 0x123
   a:   bd08        pop {r3, pc}

cortex-a5 是 armv7-a,它支持 thumb-2 就添加立即数本身而言,并且与二进制大小相关,这里没有优化,拇指为 32 位,拇指 2 为 32 位。但这只是一个例子,有时 thumb2 会产生比 thumb 更小的二进制文件。

皮质-m3

arm-none-eabi-gcc -Wall  -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -mcpu=cortex-m3 -march=armv7-m -c addimm.c -o addimmm3.o

00000000 <addimm>:
   0:   b508        push    {r3, lr}
   2:   f7ff fffe   bl  0 <fun>
   6:   f200 1023   addw    r0, r0, #291    ; 0x123
   a:   bd08        pop {r3, pc}

产生与 cortex-a5 相同的结果。对于这个简单的示例,当为 cortex-a5 和 cortex-m3 构建时,该对象的机器代码相同,大小相同

现在,如果我添加一个引导程序、一个主程序并调用此函数并填写它调用的函数以创建一个完整的链接程序

00000000 <_start>:
   0:   f000 f802   bl  8 <notmain>
   4:   e7fe        b.n 4 <_start+0x4>
    ...

00000008 <notmain>:
   8:   2005        movs    r0, #5
   a:   f000 b801   b.w 10 <addimm>
   e:   bf00        nop

00000010 <addimm>:
  10:   b508        push    {r3, lr}
  12:   f000 f803   bl  1c <fun>
  16:   f200 1023   addw    r0, r0, #291    ; 0x123
  1a:   bd08        pop {r3, pc}

0000001c <fun>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)

我们得到一个结果。addimm 函数本身的大小没有改变。使用 cortex-a5 你必须有一些手臂代码然后切换到拇指,并且可能在与库等链接时,你可能会得到手臂和拇指的混合,所以

00000000 <_start>:
   0:   eb000000    bl  8 <notmain>
   4:   eafffffe    b   4 <_start+0x4>

00000008 <notmain>:
   8:   e92d4008    push    {r3, lr}
   c:   e3a00005    mov r0, #5
  10:   fa000001    blx 1c <addimm>
  14:   e8bd4008    pop {r3, lr}
  18:   e12fff1e    bx  lr

0000001c <addimm>:
  1c:   b508        push    {r3, lr}
  1e:   f000 e804   blx 28 <fun>
  22:   f200 1023   addw    r0, r0, #291    ; 0x123
  26:   bd08        pop {r3, pc}

00000028 <fun>:
  28:   e12fff1e    bx  lr

整体较大的二进制文件,addimm 部分本身的大小没有变化。

至于链接改变对象的大小,看看这个例子

引导程序

.thumb

.thumb_func
.globl _start
_start:
    bl notmain
hang: b hang

.thumb_func
.globl dummy
dummy:
    bx lr

.code 32
.globl bounce
bounce:
    bx lr

你好ç

void dummy ( void  );
void bounce ( void  );
void notmain ( void )
{
    dummy();
    bounce();
}

单独查看 notmain 的 arm 构建,对象:

00000000 <notmain>:
   0:   e92d4800    push    {fp, lr}
   4:   e28db004    add fp, sp, #4
   8:   ebfffffe    bl  0 <dummy>
   c:   ebfffffe    bl  0 <bounce>
  10:   e24bd004    sub sp, fp, #4
  14:   e8bd4800    pop {fp, lr}
  18:   e12fff1e    bx  lr

根据调用它的内容和调用的内容,链接器可能必须添加更多代码来处理在对象外部定义的项目,从全局变量到外部函数

00008000 <_start>:
    8000:   f000 f818   bl  8034 <__notmain_from_thumb>

00008004 <hang>:
    8004:   e7fe        b.n 8004 <hang>

00008006 <dummy>:
    8006:   4770        bx  lr

00008008 <bounce>:
    8008:   e12fff1e    bx  lr

0000800c <notmain>:
    800c:   e92d4800    push    {fp, lr}
    8010:   e28db004    add fp, sp, #4
    8014:   eb000003    bl  8028 <__dummy_from_arm>
    8018:   ebfffffa    bl  8008 <bounce>
    801c:   e24bd004    sub sp, fp, #4
    8020:   e8bd4800    pop {fp, lr}
    8024:   e12fff1e    bx  lr

00008028 <__dummy_from_arm>:
    8028:   e59fc000    ldr ip, [pc]    ; 8030 <__dummy_from_arm+0x8>
    802c:   e12fff1c    bx  ip
    8030:   00008007    andeq   r8, r0, r7

00008034 <__notmain_from_thumb>:
    8034:   4778        bx  pc
    8036:   46c0        nop         ; (mov r8, r8)
    8038:   eafffff3    b   800c <notmain>
    803c:   00000000    andeq   r0, r0, r0

dummy_from_arm 和 notmain_from_thumb 都被添加,增加了二进制文件的大小。每个对象的大小没有变化,但整个二进制文件却发生了变化。bounce() 是一个手臂到手臂的功能,没有补丁,dummy() 手臂到拇指,notmain() 拇指到主。

所以你可能有一个 cortex-m3 对象和一个 cortex-a5 对象,就该对象中的代码而言,它们都是相同的。但是,取决于您将它们链接到的内容,最终在 cortex-m3 系统和 cortex-a5 系统之间有所不同,您可能会看到链接器添加或多或少的代码来解释系统差异、库、操作系统特定等等,甚至与您在二进制文件中放置对象的位置一样多,如果它必须比单条指令更远,那么链接器将添加更多代码。

这都是 gcc 特定的东西,每个工具链都将以自己的方式处理这些问题。当您使用对象和链接器模型时,这就是野兽的本性,这是一个非常好的模型,但编译器、汇编器和链接器必须协同工作以确保在链接时可以正确访问全局资源。与ARM无关,这个问题存在于许多/大多数处理器架构中,并且工具链处理每个工具链,每个版本,每个目标架构的这些问题。当我说更改对象的大小时,我真正的意思是链接器可能会向最终的二进制文件添加更多代码,以处理该对象以及它如何与其他对象交互。

于 2013-08-03T17:21:23.843 回答