比较来自两个不同制造商的两个 Thumb-2 micros。一个是 Cortex M3,一个是 A5。他们是否保证将特定的代码段编译为相同的代码大小?
1 回答
所以这里
乐趣.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无关,这个问题存在于许多/大多数处理器架构中,并且工具链处理每个工具链,每个版本,每个目标架构的这些问题。当我说更改对象的大小时,我真正的意思是链接器可能会向最终的二进制文件添加更多代码,以处理该对象以及它如何与其他对象交互。