搜索
bottom↓
回复: 12

这里高手多啊,请教大家。GCC Link出现的奇怪问题。。。。。。。。。。。。。。。。。

[复制链接]

出0入0汤圆

发表于 2010-8-23 15:16:33 | 显示全部楼层 |阅读模式
最近在学习2440的裸机程序,忽然碰到个问题,请教大家。


main函数如下:
int main()
{
        int i;
        char c[43]="   teachers hard you!\r\n    Thank you\r\n   \0";  
       //如果此处定义的是指针的话就没问题,为什么?     
       
        return 0;
}

在上面,如果把C定义为数组则在用ARM-LINUX-LD链接的话会会出现如下错误:

(原文件名: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)

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2010-8-23 15:31:10 | 显示全部楼层
memcpy的调用是未定义?

加入标准库文件怎么样呢

出0入0汤圆

发表于 2010-8-23 15:33:13 | 显示全部楼层
字符串一般放在 .rodata 段里。

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

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

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

出0入0汤圆

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

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

出0入0汤圆

发表于 2010-8-23 17:08:37 | 显示全部楼层
另外,

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

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

出0入0汤圆

发表于 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 吧

出0入0汤圆

 楼主| 发表于 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函数吗?

出0入0汤圆

发表于 2010-8-23 21:02:54 | 显示全部楼层
回复【6楼】youki1234  
-----------------------------------------------------------------------

编译的时候是不会出错的,生成的.o文件中会包含memcpy的relocation标识。
在做链接时,链接器会根据最终memcpy所在位置去做relocation。
此时,如果不能找到memcpy,也就无法知道它的最终位置在什么地方了,relocation也就无从谈起。

另外,

int main()
{
int i;
char c[43]="   teachers hard you!\r\n    Thank you\r\n   \0";  
       //如果此处定义的是指针的话就没问题,为什么?     

return 0;
}

c[43]没有被别的过程使用,所以在做 -O2 优化时,这个函数会被优化的不剩什么东西了,你可以用下面的命令来反汇编 main.o
然后看看结果就都清楚了。

$ arm-linux-objdump -d main.o

出0入0汤圆

 楼主| 发表于 2010-8-23 21:13:58 | 显示全部楼层
回复【7楼】mcu.runner
回复【6楼】youki1234   
-----------------------------------------------------------------------
编译的时候是不会出错的,生成的.o文件中会包含memcpy的relocation标识。
在做链接时,链接器会根据最终memcpy所在位置去做relocation。
此时,如果不能找到memcpy,也就无法知道它的最终位置在什么地方了,relocation也就无从谈起。
另外,
int main()
{
int i;
char c[43]="   teachers hard you!\r\n    thank you\r\n   \0";   
       //如果此处定义的是指针的话就没问题,为什么?      
return 0;
}
c[43]没有被别的过程使用,所以在做 -o2 优化......
-----------------------------------------------------------------------

明白了,非常感谢!

出0入0汤圆

发表于 2010-8-23 21:15:15 | 显示全部楼层
可以使用arm-linux-ld 把arm-linux-gcc交叉编译器的lib链接进来

出0入0汤圆

 楼主| 发表于 2010-8-24 07:48:02 | 显示全部楼层
但还有一个疑惑,

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

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

出0入0汤圆

发表于 2010-8-24 08:15:27 | 显示全部楼层
回复【10楼】youki1234  
-----------------------------------------------------------------------

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

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

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

出0入0汤圆

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

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

明白了,谢谢
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 20:02

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表