这里高手多啊,请教大家。GCC Link出现的奇怪问题。。。。。。。。。。。。。。。。。
最近在学习2440的裸机程序,忽然碰到个问题,请教大家。main函数如下:
int main()
{
int i;
char c=" teachers hard you!\r\n Thank you\r\n \0";
//如果此处定义的是指针的话就没问题,为什么?
return 0;
}
在上面,如果把C定义为数组则在用ARM-LINUX-LD链接的话会会出现如下错误:
http://cache.amobbs.com/bbs_upload782111/files_32/ourdev_577175.JPG
(原文件名:df.JPG)
如果定义为指针的话就不会,始终没有想明白。。。。
Makefile链接文件如下所示:
obj :=head.o init.o uart.o main.o
uart.bin : $(obj)
arm-linux-ld -Tuart.lds -o uart_elf $^
arm-linux-objcopy -O binary -S uart_elf $@
%.o:%.c
arm-linux-gcc -Wall -o2 -c -o $@ $<
%.o:%.s
arm-linux-gcc -Wall -o2 -c -o $@ $<
clean:
rm -f uart.bin uart_elf *.o
和lds链接文件如下所示:
SECTIONS
{
. =0x30000000;
.text : { *(.text) }
.rodata ALIGN(4) : {*(.rodata)}
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4): { *(.bss)*(COMMON) }
}
整个代码如下
点击此处下载 ourdev_577176.rar(文件大小:5K) (原文件名:123.rar) memcpy的调用是未定义?
加入标准库文件怎么样呢 字符串一般放在 .rodata 段里。
函数里定义的局部变量一般放在栈上(由sp寄存器动态决定)。所以,字符串和局部变量不在一个内存区域里。
当编译器编译这段代码的时候会作这样的处理:
1、当局部变量定义的是数组时,编译器会自动生成一个memcpy的函数调用,把.rodata段里的字符串拷贝到栈空间。
2、当局部变量定义的是指针时,编译器只需要把.rodata中字符串的地址赋给这个指针变量就可以了。
链接时使用的是ld,这时候应该把所有相关的库显式给出来,否则就会报没有相关 symbol 回复【2楼】mcu.runner
字符串一般放在 .rodata 段里。
函数里定义的局部变量一般放在栈上(由sp寄存器动态决定)。所以,字符串和局部变量不在一个内存区域里。
当编译器编译这段代码的时候会作这样的处理:
1、当局部变量定义的是数组时,编译器会自动生成一个memcpy的函数调用,把.rodata段里的字符串拷贝到栈空间。
2、当局部变量定义的是指针时,编译器只需要把.rodata中字符串的地址赋给这个指针变量就可以了。
链接时使用的是ld,这时候应该把所有相关的库显式给出来,否则就会报没有相关 symbol
-----------------------------------------------------------------------
请问如何显式的给出呢?在Ld命令后? 另外,
%.o:%.c
arm-linux-gcc -Wall -o2 -c -o $@ $<
中的 -o2 是错的,应该是 -O2 才对。但是,如果使用 -O2 优化,可能 main.c 就什么也剩不下了..... 回复【3楼】youki1234
-----------------------------------------------------------------------
arm-linux-ld -Tuart.lds -o uart_elf $^
可以用
arm-linux-ld -Tuart.lds -o uart_elf $^ -lc -lgcc
但是如果是裸奔程序, -lc 还不能用(arm-linux-ld 会去链 glibc,问题就复杂多了...),LZ自己写个 memcpy 吧 回复【4楼】mcu.runner
另外,
%.o:%.c
arm-linux-gcc -wall -o2 -c -o $@ $<
中的 -o2 是错的,应该是 -o2 才对。但是,如果使用 -o2 优化,可能 main.c 就什么也剩不下了.....
-----------------------------------------------------------------------
恩,应该是O2.
·······································
但好像这段代码如果用arm-linux-gcc -wall -o2 -o $@ $<命令编译时就不会出现问题,难道先用-c生成.o文件后再连接就会出现问题?
难道说在连接的时候连接器会调用memcpy函数吗? 回复【6楼】youki1234
-----------------------------------------------------------------------
编译的时候是不会出错的,生成的.o文件中会包含memcpy的relocation标识。
在做链接时,链接器会根据最终memcpy所在位置去做relocation。
此时,如果不能找到memcpy,也就无法知道它的最终位置在什么地方了,relocation也就无从谈起。
另外,
int main()
{
int i;
char c=" teachers hard you!\r\n Thank you\r\n \0";
//如果此处定义的是指针的话就没问题,为什么?
return 0;
}
c没有被别的过程使用,所以在做 -O2 优化时,这个函数会被优化的不剩什么东西了,你可以用下面的命令来反汇编 main.o
然后看看结果就都清楚了。
$ arm-linux-objdump -d main.o 回复【7楼】mcu.runner
回复【6楼】youki1234
-----------------------------------------------------------------------
编译的时候是不会出错的,生成的.o文件中会包含memcpy的relocation标识。
在做链接时,链接器会根据最终memcpy所在位置去做relocation。
此时,如果不能找到memcpy,也就无法知道它的最终位置在什么地方了,relocation也就无从谈起。
另外,
int main()
{
int i;
char c=" teachers hard you!\r\n thank you\r\n \0";
//如果此处定义的是指针的话就没问题,为什么?
return 0;
}
c没有被别的过程使用,所以在做 -o2 优化......
-----------------------------------------------------------------------
明白了,非常感谢! 可以使用arm-linux-ld 把arm-linux-gcc交叉编译器的lib链接进来 但还有一个疑惑,
为什么直接用GCC命令就不会有问题呢?
如:GCC -O AAA mian.c ......
难道默认的LD脚本。。。 回复【10楼】youki1234
-----------------------------------------------------------------------
注意,这里用的是gcc而不是ld
用 gcc 时,链接过程由 gcc 调用 ld 完成,链接的库定义在 spec 文件中。
这个 spec 文件就在 gcc 的安装目录下(具体位置记不清了,汗!)。
ld 脚本一般定义的是最后生成的 elf 文件中各个段在内存中的分布情况,
它不是用来指示链接的库文件的。 回复【11楼】mcu.runner
回复【10楼】youki1234
-----------------------------------------------------------------------
注意,这里用的是gcc而不是ld
用 gcc 时,链接过程由 gcc 调用 ld 完成,链接的库定义在 spec 文件中。
这个 spec 文件就在 gcc 的安装目录下(具体位置记不清了,汗!)。
ld 脚本一般定义的是最后生成的 elf 文件中各个段在内存中的分布情况,
它不是用来指示链接的库文件的。
-----------------------------------------------------------------------
明白了,谢谢
页:
[1]