youki1234 发表于 2010-8-23 15:16:33

这里高手多啊,请教大家。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)

yajira 发表于 2010-8-23 15:31:10

memcpy的调用是未定义?

加入标准库文件怎么样呢

mcu.runner 发表于 2010-8-23 15:33:13

字符串一般放在 .rodata 段里。

函数里定义的局部变量一般放在栈上(由sp寄存器动态决定)。所以,字符串和局部变量不在一个内存区域里。

当编译器编译这段代码的时候会作这样的处理:
1、当局部变量定义的是数组时,编译器会自动生成一个memcpy的函数调用,把.rodata段里的字符串拷贝到栈空间。
2、当局部变量定义的是指针时,编译器只需要把.rodata中字符串的地址赋给这个指针变量就可以了。

链接时使用的是ld,这时候应该把所有相关的库显式给出来,否则就会报没有相关 symbol

youki1234 发表于 2010-8-23 17:08:26

回复【2楼】mcu.runner
字符串一般放在 .rodata 段里。
函数里定义的局部变量一般放在栈上(由sp寄存器动态决定)。所以,字符串和局部变量不在一个内存区域里。
当编译器编译这段代码的时候会作这样的处理:
1、当局部变量定义的是数组时,编译器会自动生成一个memcpy的函数调用,把.rodata段里的字符串拷贝到栈空间。
2、当局部变量定义的是指针时,编译器只需要把.rodata中字符串的地址赋给这个指针变量就可以了。
链接时使用的是ld,这时候应该把所有相关的库显式给出来,否则就会报没有相关 symbol
-----------------------------------------------------------------------

请问如何显式的给出呢?在Ld命令后?

mcu.runner 发表于 2010-8-23 17:08:37

另外,

%.o:%.c
arm-linux-gcc -Wall -o2 -c -o $@ $<

中的 -o2 是错的,应该是 -O2 才对。但是,如果使用 -O2 优化,可能 main.c 就什么也剩不下了.....

mcu.runner 发表于 2010-8-23 17:13:41

回复【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 吧

youki1234 发表于 2010-8-23 20:04:58

回复【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函数吗?

mcu.runner 发表于 2010-8-23 21:02:54

回复【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

youki1234 发表于 2010-8-23 21:13:58

回复【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 优化......
-----------------------------------------------------------------------

明白了,非常感谢!

simonccn 发表于 2010-8-23 21:15:15

可以使用arm-linux-ld 把arm-linux-gcc交叉编译器的lib链接进来

youki1234 发表于 2010-8-24 07:48:02

但还有一个疑惑,

为什么直接用GCC命令就不会有问题呢?

如:GCC -O AAA mian.c ......
难道默认的LD脚本。。。

mcu.runner 发表于 2010-8-24 08:15:27

回复【10楼】youki1234
-----------------------------------------------------------------------

注意,这里用的是gcc而不是ld

用 gcc 时,链接过程由 gcc 调用 ld 完成,链接的库定义在 spec 文件中。
这个 spec 文件就在 gcc 的安装目录下(具体位置记不清了,汗!)。

ld 脚本一般定义的是最后生成的 elf 文件中各个段在内存中的分布情况,
它不是用来指示链接的库文件的。

youki1234 发表于 2010-8-24 10:26:29

回复【11楼】mcu.runner
回复【10楼】youki1234   
-----------------------------------------------------------------------
注意,这里用的是gcc而不是ld
用 gcc 时,链接过程由 gcc 调用 ld 完成,链接的库定义在 spec 文件中。
这个 spec 文件就在 gcc 的安装目录下(具体位置记不清了,汗!)。
ld 脚本一般定义的是最后生成的 elf 文件中各个段在内存中的分布情况,
它不是用来指示链接的库文件的。

-----------------------------------------------------------------------

明白了,谢谢
页: [1]
查看完整版本: 这里高手多啊,请教大家。GCC Link出现的奇怪问题。。。。。。。。。。。。。。。。。