编译器编译老师讲的视频,我在看视频过程中一直用的4.3.2版本交叉编译工具编译项目,当我看到视频的第11课第005节的时候,演示自己实现printf裸机打印,里面用到了lib1funcs.S文件,我编译的时候发现会遇到这样一个错误
ARM-linux-gcc -c -o LED.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
arm-linux-gcc -c -o my_printf.o my_printf.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
my_printf.o: In function `out_num':
my_printf.c:(.text+0x120): undefined reference to `__aeabi_uidivmod'
my_printf.c:(.text+0x158): undefined reference to `__aeabi_uidiv'
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
这是因为编译器的库没有实现除法运算,可是老师演示的时候明明可以编译通过啊,而且代码也反复检查了一下,没有不同,后来了解到老师用的是3.4.5版本的交叉编译工具,换成3.4.5版本的编译工具,果然可以编译通过。但是我想试试4.3.2版本能不能编译通过。
首先这个错误提示说明是一个未定义引用的错误,说的是my_printf.c文件out_num方法有问题,根据__aeabi_uidivmod,和__aeabi_uidiv猜想应该是除法实现的问题,这里用到了lib1funcs.S这个除法库文件,于是我在里面搜索__aeabi_uidiv和__aeabi_uidivmod,可是发现找不到这两个关键字的定义,事实表明应该是4.3.2版本的编译工具需要找这两个关键字的定义,但是找不到。于是猜测应该是这个lib1funcs.S是比较老版本的库文件,可是这个较新版本的去哪找呢,除法运算在u-boot和Linux内核里肯定实现了,就到这两个里面去找这个文件。
4.3.2编译通过的两个项目版本分别是u-boot-2012.04.01以及linux-3.4.2,就到这两个项目中找,你会发现u-boot里面没有这个文件,u-boot肯定实现了,但是不是用这个来实现的,我们到linux内核里找,你会搜索到如下结果:
song@dev:/work/hardware/009_uart$ find /work/system/linux-3.4.2 -name "lib1funcs.S"
/work/system/linux-3.4.2/arch/arm/lib/lib1funcs.S
/work/system/linux-3.4.2/arch/arm/boot/compressed/lib1funcs.S
/work/system/linux-3.4.2/arch/arm/lib/lib1funcs.S,这个文件应该就是我们找的库文件把他copy到项目里,然后make
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
lib1funcs.S:36:27: error: linux/linkage.h: No such file or directory
lib1funcs.S:37:27: error: asm/assembler.h: No such file or directory
lib1funcs.S:38:24: error: asm/unwind.h: No such file or directory
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
遇到如上错误,提示我们找不到这些头文件,我们没有引用怎么可能找到,对比以前的lib1funcs.S不需要这些头文件,我们直接去掉就行。保存make
song@dev:/work/hardware/009_uart$ make
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
lib1funcs.S: Assembler messages:
lib1funcs.S:175: Error: bad instruction `entry(__udivsi3)'
lib1funcs.S:176: Error: bad instruction `entry(__aeabi_uidiv)'
lib1funcs.S:177: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:201: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:202: Error: bad instruction `endproc(__udivsi3)'
lib1funcs.S:203: Error: bad instruction `endproc(__aeabi_uidiv)'
lib1funcs.S:205: Error: bad instruction `entry(__umodsi3)'
lib1funcs.S:206: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:220: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:221: Error: bad instruction `endproc(__umodsi3)'
lib1funcs.S:223: Error: bad instruction `entry(__divsi3)'
lib1funcs.S:224: Error: bad instruction `entry(__aeabi_idiv)'
lib1funcs.S:225: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:262: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:263: Error: bad instruction `endproc(__divsi3)'
lib1funcs.S:264: Error: bad instruction `endproc(__aeabi_idiv)'
lib1funcs.S:266: Error: bad instruction `entry(__modsi3)'
lib1funcs.S:267: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:287: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:288: Error: bad instruction `endproc(__modsi3)'
lib1funcs.S:350: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:351: Error: bad instruction `unwind(.pad #4)'
lib1funcs.S:352: Error: bad instruction `unwind(.save {lr})'
lib1funcs.S:357: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:358: Error: bad instruction `endproc(Ldiv0)'
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
这些错误,从意思应该是也是对这些定义不理解,应该是去掉头文件引起来的,也就是说头文件中有这些的定义,我们对比老的lib1funcs开头有一些宏定义我们先加上,其中有entry的宏定义,我们可以猜想这些都是在头文件里的宏定义,其实你去linux内核里找这个头文件#include 在这里就可以找到entry的宏定义。然后保存make
还会报这种错误,也是没有写宏定义
lib1funcs.S:357: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:358: Error: bad instruction `endproc(Ldiv0)'
但是我们对别老的lib1funcs.S发现这些都没有,所以这些关键字标识符我们先去掉只要是UNWIND和ENDPROC开头的都去掉,然后make
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
arm-linux-gcc -c -o my_printf.o my_printf.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
my_printf.o: In function `out_num':
my_printf.c:(.text+0x120): undefined reference to `__aeabi_uidivmod'
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
你会发现还是报未定义的错误,在lib1funcs.S搜索这个定义,它的上面有个#IFdef CONFIG_AEABI,需要先定义这个宏定义,我们在开头加一句 #define CONFIG_AEABI 1,然后保存make
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
arm-linux-gcc -c -o my_printf.o my_printf.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
arm-linux-ld: section .data [00000e80 -> 00000e8f] overlaps section .rodata [00000d74 -> 00000e9b]
arm-linux-ld: uart.elf: section .data lma 0xe80 overlaps previous sections
lib1funcs.o: In function `Ldiv0':
(.text+0x3ec): undefined reference to `__div0'
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1
还有一个未定义搜索lib1funcs.S,是在最后相对跳转到一个c函数里面执行,我们对比老的lib1funcs.S发现这里注释掉了,我们也注释掉,然后保存make
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
arm-linux-gcc -c -o my_printf.o my_printf.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
arm-linux-ld: section .data [00000e80 -> 00000e8f] overlaps section .rodata [00000d74 -> 00000e9b]
arm-linux-ld: uart.elf: section .data lma 0xe80 overlaps previous sections
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 1,
你可能会遇到这个问题这个应该是代码段太长了,超过了定义的数据段的位置,可以自己适当延长代码段,我试了一下用0xea0就可以,到此第一期arm加强版demo程序009-uart移植4.3.2编译器完毕。
在后面的lcd那里的除法解决方案里需要用到libgcc.a库,我当时用的是/usr/local/arm/4.3.2/lib/gcc/arm-none-linux-gnueabi/4.3.2/libgcc.a这个文件,在后面的adc实验的时候发现这个库无法解决浮点数除法的问题,解决了一段时间,最后还是微信请教了韦老师,老师最后发现是我用的libgcc.a文件错误,应该用4.3.2/lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t/libgcc.a这个位置的libgcc.a文件
备注:这里我用的是009_uart项目重新走了一遍。
0