【发布时间】:2014-03-20 18:33:49
【问题描述】:
我正在将代码编译到 ARM,生成的程序集不是我所期望的。
以下代码:
#include <stdint.h>
extern uint8_t* a;
extern uint8_t b[];
void teste(void)
{
*a = b[1];
b[2] = *a;
}
在 ARM GCC 4.7.3 和 ARM GCC 4.8.3 上编译时生成以下 asm:
00000000 <teste>:
0: 4a04 ldr r2, [pc, #16] ; (14 <teste+0x14>)
2: 4b05 ldr r3, [pc, #20] ; (18 <teste+0x18>)
4: 6811 ldr r1, [r2, #0]
6: 7858 ldrb r0, [r3, #1]
8: 7008 strb r0, [r1, #0]
a: 6812 ldr r2, [r2, #0]
c: 7812 ldrb r2, [r2, #0]
e: 709a strb r2, [r3, #2]
10: 4770 bx lr
12: bf00 nop
...
Obs:r2得到a的地址,r3得到b的地址。
这不是我想要的。 为了让 asm 正常工作,我必须这样做
extern uint8_t a[];
并生成以下asm:
00000000 <teste>:
0: 4a02 ldr r2, [pc, #8] ; (c <teste+0xc>)
2: 4903 ldr r1, [pc, #12] ; (10 <teste+0x10>)
4: 7853 ldrb r3, [r2, #1]
6: 7093 strb r3, [r2, #2]
8: 700b strb r3, [r1, #0]
a: 4770 bx lr
...
Obs:r2得到b的地址,r1得到a的地址。
注意:我做了一个动态链接来输入正确的“a”和“b”值。所以在代码的开头 r2 和 r3(在第一个代码上)或 r1 和 r2(在第二个代码上)得到正确的值。
要编译,我使用以下内容:
arm-none-eabi-gcc.exe -c code.c -o code.o -mthumb -mcpu=cortex-m4 -O2 -mlong-calls -mword-relocations -mabi=atpcs -mfloat-abi=soft -mcaller-super-interworking
arm-none-eabi-ld.exe -o code.elf code.o --relocatable --strip-all --discard-all --embedded-relocs
有人知道为什么第一种方法不能正常工作吗?
“a”是分配在内存中的字节变量的地址,因此将其声明为向量是没有意义的。
感谢您的帮助。
【问题讨论】:
-
也许阅读 this 会有所帮助。
-
变量为
extern并没有什么神奇之处(除了您不需要指定数组中元素的数量)。如果您删除了externs,并为数组指定了大小,您将(应该)看到相同的代码。 -
extern加入其中是因为它提供了一个机会,可以意外地以略微不兼容的方式重新声明其他地方定义的内容。在数组被正确声明为数组的文件中,您可以使用指针表示法访问它 - 这里的问题是它被声明了两次,一次(在另一个文件中)作为数组,一次(在这个文件中)作为简单的指针,那些不兼容实现。 -
没有看到实际的声明,我无法确定它是否存在微妙的不兼容。我假设
extern的类型与声明的类型匹配。 -
问题在于,在 C 语言中,人们倾向于混淆数组和指针,因为在大多数情况下,数组的行为就好像它们是指向第一个元素的指针。当你在封面下看时,你会发现它们实际上是不同的。如果你将一个变量声明为一个数组,然后告诉另一个编译单元它是一个指针(使用
extern),那么代码将编译和链接,但它不会正确运行,因为两个编译单元会查看以两种完全不同的方式使用同一块内存。