1、这个错误提示说明是一个未定义引用的错误,根据__aeabi_uidivmod,和__aeabi_uidiv猜想应该是除法实现的问题(为什么就能得出是除法实现的问题?根据英文名吗?可是我查了下,没有这个英文。)。
2、这里用到了lib1funcs.S这个除法库文件,于是在里面搜索__aeabi_uidiv和__aeabi_uidivmod,找不到这两个关键字的定义。
说明应该是4.3.2版本的编译工具需要找这两个关键字的定义,但是找不到。
3、猜测应该是这个lib1funcs.S是比较老版本的库文件,可是这个较新版本的去哪找呢,除法运算在u-boot和Linux内核里肯定实现了,就到这两个里面去找这个文件。
4、4.3.2编译通过的两个项目版本分别是u-boot-2012.04.01以及linux-3.4.2,就到这两个项目中找,你会发现u-boot里面没有这个文件,u-boot肯定实现了,但是不是用这个来实现的,我们到linux内核里找:
find /work/projects/linux-3.4.2 -name "lib1funcs.S"
搜索结果:
./arch/arm/lib/lib1funcs.S
./arch/arm/boot/compressed/lib1funcs.S
登录后复制
5、/work/system/linux-3.4.2/arch/arm/lib/lib1funcs.S,这个文件应该就是我们找的库文件。
把他copy到项目里,然后make。
编译结果:
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:11: recipe for target 'lib1funcs.o' failed
make: *** [lib1funcs.o] Error 1
登录后复制
提示我们找不到这些头文件,对比以前的lib1funcs.S不需要这些头文件。
所以我们把头文件注释掉:
35 /*
36 #include <linux/linkage.h>
37 #include <asm/assembler.h>
38 #include <asm/unwind.h>
39 */
登录后复制
6、再次编译,出现如下错误:
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
lib1funcs.S: Assembler messages:
lib1funcs.S:181: Error: bad instruction `entry(__udivsi3)'
lib1funcs.S:182: Error: bad instruction `entry(__aeabi_uidiv)'
lib1funcs.S:183: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:207: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:208: Error: bad instruction `endproc(__udivsi3)'
lib1funcs.S:209: Error: bad instruction `endproc(__aeabi_uidiv)'
lib1funcs.S:211: Error: bad instruction `entry(__umodsi3)'
lib1funcs.S:212: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:226: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:227: Error: bad instruction `endproc(__umodsi3)'
lib1funcs.S:229: Error: bad instruction `entry(__divsi3)'
lib1funcs.S:230: Error: bad instruction `entry(__aeabi_idiv)'
lib1funcs.S:231: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:268: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:269: Error: bad instruction `endproc(__divsi3)'
lib1funcs.S:270: Error: bad instruction `endproc(__aeabi_idiv)'
lib1funcs.S:272: Error: bad instruction `entry(__modsi3)'
lib1funcs.S:273: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:293: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:294: Error: bad instruction `endproc(__modsi3)'
lib1funcs.S:356: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:357: Error: bad instruction `unwind(.pad #4)'
lib1funcs.S:358: Error: bad instruction `unwind(.save {lr})'
lib1funcs.S:363: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:364: Error: bad instruction `endproc(Ldiv0)'
Makefile:11: recipe for target 'lib1funcs.o' failed
make: *** [lib1funcs.o] Error 1
登录后复制
应该是去掉头文件引起的编译器对定义不理解。
对比老版本的lib1funcs开头有一些宏定义我们先加上:
#define ALIGN .align 4,0x90
#define __LINUX_ARM_ARCH__ 1
#define ENTRY(name) \
.globl name\
ALIGN\
name:
登录后复制
其中有entry的宏定义,我们可以猜想这些都是在头文件里的宏定义,其实你去linux内核里找这个头文件#include <linux/linkage.h>在这里就可以找到entry的宏定义。
7、再次编译,出现错误:
book@www.100ask.org:/work/test$ make
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
lib1funcs.S: Assembler messages:
lib1funcs.S:192: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:216: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:217: Error: bad instruction `endproc(__udivsi3)'
lib1funcs.S:218: Error: bad instruction `endproc(__aeabi_uidiv)'
lib1funcs.S:221: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:235: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:236: Error: bad instruction `endproc(__umodsi3)'
lib1funcs.S:240: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:277: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:278: Error: bad instruction `endproc(__divsi3)'
lib1funcs.S:279: Error: bad instruction `endproc(__aeabi_idiv)'
lib1funcs.S:282: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:302: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:303: Error: bad instruction `endproc(__modsi3)'
lib1funcs.S:365: Error: bad instruction `unwind(.fnstart)'
lib1funcs.S:366: Error: bad instruction `unwind(.pad #4)'
lib1funcs.S:367: Error: bad instruction `unwind(.save {lr})'
lib1funcs.S:372: Error: bad instruction `unwind(.fnend)'
lib1funcs.S:373: Error: bad instruction `endproc(Ldiv0)'
Makefile:11: recipe for target 'lib1funcs.o' failed
make: *** [lib1funcs.o] Error 1
登录后复制
unwind() 和unwind()的宏定义老版本里没有,怎么办呢?
全部注释掉:
#UNWIND(.fnend)
#ENDPROC(__modsi3)
登录后复制
8、再次编译,出现错误:
book@www.100ask.org:/work/test$ make
arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
#arm-linux-ld -Ttext 0 -Tdata 0x30000000 start.o led.o uart.o init.o main.o -o sdram.elf
arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o exception.o interrupt.o timer.o nor_flash.o my_printf.o string_utils.o lib1funcs.o -o sdram.elf
my_printf.o: In function `out_num':
my_printf.c:(.text+0x120): undefined reference to `__aeabi_uidivmod'
lib。
LPC2103
LP
你可以自己写一个汇编的程序,把Nand Flash 中的程序搬到SDRAM中。因为S3C2410有Nor Flash和Nand Flash有两种启动方式,所以在搬移过程中略有不同。如果用Nand Flash启动可以使用下面的代码,至于Nor Flash启动就相对简单了,你可以自己研究一下。文件1.head.s
@ 文件 head.s
@ 作用:关闭看门狗、SDRAM 的初始化设置、搬移 Nand Flash 4K 以后
@ 的代码到 SDRAM 的指定位置、执行 SDRAM 中的代码
.text
.global _start
_start:
ldr r0, =0x53000000 @ Close Watch Dog Timer
mov r1, #0x0
str r1, [r0]
bl memory_setup @ Initialize memory setting
bl flash_to_sdram @ Copy code to sdram
ldr sp, =0x34000000 @ Set stack pointer
ldr pc, =main @ execute the code in SDRAM
文件2:flash.s
@ 文件 flash.s
@ 作用:设置 Nand Flash 的控制寄存器、读取 Nand Flash
@ 中的代码到 SDRAM 的指定位置
.equ NFCONF, 0x4e000000
.equ NFCMD, 0x4e000004
.equ NFADDR, 0x4e000008
.equ NFDATA, 0x4e00000c
.equ NFSTAT, 0x4e000010
.equ NFECC, 0x4e000014
.global flash_to_sdram
flash_to_sdram:
@ Save return addr
mov r10,lr
@ Initialize Nand Flash
mov r0,#NFCONF
ldr r1,=0xf830
str r1,[r0]
@ First reset and enable Nand Flash
ldr r1,[r0]
bic r1, r1, #0x800
str r1,[r0]
ldr r2,=NFCMD
mov r3,#0xff
str r3,[r2]
@ for delay
mov r3, #0x0a
1:
subs r3, r3, #1
bne 1b
@ Wait until Nand Flash bit0 is 1
wait_nfstat:
ldr r2,=NFSTAT
ldr r3,[r2]
tst r3,#0x01
beq wait_nfstat
@ Disable Nand Flash
ldr r0,=NFCONF
ldr r1,[r0]
orr r1,r1,#0x8000
str r1,[r0]
@ Initialzie stack
ldr sp,=4096
@ Set arguments and call
@ function nand_read defined in nand_read.c
ldr r0,=0x30000000
mov r1,#4096
mov r2,#1024
bl nand_read
@ return
mov pc,r10
文件3:interrupt.c
/*
* 文件 interrupt.c
* 作用:设置并响应按键中断
*/
#include "printf.h"
#define GPECON (*(volatile unsigned long *)0x56000040)
#define GPEDAT (*(volatile unsigned long *)0x56000044)
#define GPEUP (*(volatile unsigned long *)0x56000048)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
#define GPFUP (*(volatile unsigned long *)0x56000058)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define GPGDAT (*(volatile unsigned long *)0x56000064)
#define GPGUP (*(volatile unsigned long *)0x56000068)
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define INTMSK (*(volatile unsigned long *)0X4a000008)
#define PRIORITY (*(volatile unsigned long *)0x4a00000c)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
#define INTPND (*(volatile unsigned long *)0X4a000010)
#define SRCPND (*(volatile unsigned long *)0X4a000000)
#define BIT_EINT0 (0x1 <<0)
#define BIT_EINT2 (0x1 <<2)
#define BIT_EINT8_23 (0x1 <<5)
#define SET_KEY_INTERRUPT_REG() ({ \
GPGCON = (GPGCON &(~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) \
GPGDAT = GPGDAT &(~((1<<6)|(1<<2))) \
GPECON = (GPECON &(~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22))\
GPEDAT = GPEDAT &(~((1<<13)|(1<<11))) \
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) \
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) \
})
__inline void ClearPending(int bit)
{
SRCPND = bit
INTPND = bit
}
void init_irq( ) {
GPFCON = ((0x1<<8) | (0x1 <<10) | (0x1 <<12) | (0x1 <<14)) // Set the led D9~D12 output
/*
GPGCON = (GPGCON &(~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) // GPGCON6,2 set output
// GPGCON6:KSCAN1
// GPGCON2:KSCAN3
GPGDAT = GPGDAT &(~((1<<6)|(1<<2))) // GPGDAT6,2 output 0
GPECON = (GPECON &(~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22)) // GPECON13,11 set output
GPEDAT = GPEDAT &(~((1<<13)|(1<<11))) // GPEDAT13,11 output 0
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) // GPGCON11,3 set EINT
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) // GPFDAT2,0 set EINT
*/
// Use the defined micro instead of above code
SET_KEY_INTERRUPT_REG()
GPFUP |= (1<<0) | (1<<2) // Up
GPGUP |= (1<<3) | (1<<11) // Up
EINTPEND |= (1 <<19) | (1 <<11) // Clear eint 11,19
EINTMASK &= (~((1 <<19) | (1 <<11)))// Enable EINT11,19
ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23)// Enable EINT0,2 and the EINT8_23
INTMSK &= (~0x25)
return
}
int Key_Scan( void )
{
int i
for(i = 0i <1000 i++)
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (0<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 16
else if( (GPFDAT&(1<<2)) == 0 ) return 15
else if( (GPGDAT&(1<<3)) == 0 ) return 14
else if( (GPGDAT&(1<<11)) == 0 ) return 13
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (0<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 11
else if( (GPFDAT&(1<<2)) == 0 ) return 8
else if( (GPGDAT&(1<<3)) == 0 ) return 5
else if( (GPGDAT&(1<<11)) == 0 ) return 2
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (0<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 10
else if( (GPFDAT&(1<<2)) == 0 ) return 7
else if( (GPGDAT&(1<<3)) == 0 ) return 4
else if( (GPGDAT&(1<<11)) == 0 ) return 1
GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) //GPG6,2 output 0
GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (0<<13) | (1<<11) //GPE13,11 output 0
if( (GPFDAT&(1<<0)) == 0 ) return 12
else if( (GPFDAT&(1<<2)) == 0 ) return 9
else if( (GPGDAT&(1<<3)) == 0 ) return 6
else if( (GPGDAT&(1<<11)) == 0 ) return 3
else return 0xff
}
void EINT_Handle( void ) {
GPGCON = (GPGCON &(~((3<<22)|(3<<6)))) | ((0<<22)|(0<<6)) //GPG11,3 set input
GPFCON = (GPFCON &(~((3<<4)|(3<<0)))) | ((0<<4)|(0<<0)) //GPF2, 0 set input
if(INTPND==BIT_EINT8_23) {
if(EINTPEND&(1<<11))
EINTPEND |= 1<<11
if(EINTPEND&(1<<19))
EINTPEND |= 1<<19
ClearPending(BIT_EINT8_23)
}
else if(INTPND==BIT_EINT0) {
ClearPending(BIT_EINT0)
} else if(INTPND==BIT_EINT2) {
ClearPending(BIT_EINT2)
}
int key = Key_Scan()
if( key != 0xff ) {
uart_printf( "K%d is pressed!\n", key )
GPFDAT = ~(key <<4)
}
SET_KEY_INTERRUPT_REG()
return
}
文件4:mem.s
@ 文件 mem.s
@ 作用:SDRAM 的初始化设置
@ 关于初始化的更多细节,请参考我的前一篇随笔
.global memory_setup @ 导出 memory_setup, 使其对链接器可见
memory_setup:
mov r1, #0x48000000
adrl r2, mem_cfg_val
add r3, r1, #13*4
1:
@ write initial values to registers
ldr r4, [r2], #4
str r4, [r1], #4
cmp r1, r3
bne 1b
mov pc, lr
.align 4
mem_cfg_val:
.long 0x22111110 @ BWSCON
.long 0x00000700 @ BANKCON0
.long 0x00000700 @ BANKCON1
.long 0x00000700 @ BANKCON2
.long 0x00000700 @ BANKCON3
.long 0x00000700 @ BANKCON4
.long 0x00000700 @ BANKCON5
.long 0x00018005 @ BANKCON6
.long 0x00018005 @ BANKCON7 9bit
.long 0x008e07a3 @ REFRESH
.long 0x000000b2 @ BANKSIZE
.long 0x00000030 @ MRSRB6
.long 0x00000030 @ MRSRB7
文件5:nand_read.c
/* 文件 nand_read.c
* 作用:从 Nand Flash 中读取一块数据到 SDRAM 中的指定位置
*/
#define NFCONF (*(volatile unsigned long *)0x4e000000)
#define NFCMD (*(volatile unsigned long *)0x4e000004)
#define NFADDR (*(volatile unsigned long *)0x4e000008)
#define NFDATA (*(volatile unsigned long *)0x4e00000c)
#define NFSTAT (*(volatile unsigned long *)0x4e000010)
#define NFECC (*(volatile unsigned long *)0x4e000014)
#define NAND_SECTOR_SIZE 512
#define NAND_BLOCK_MASK 0x1ff
void wait_idle() {
int i
for (i = 0i <50000++i)
}
int nand_read(unsigned char *buf, unsigned long start_addr, int size){
int i, j
/*
* detect the argument
*/
if ((start_addr &NAND_BLOCK_MASK) || (size &NAND_BLOCK_MASK)) {
return -1
}
/* chip Enable */
NFCONF &= ~0x800
for (i=0i<10i++) {
}
for (i=start_addri <(start_addr + size)i+=NAND_SECTOR_SIZE) {
NFCMD = 0
/* Write Address */
NFADDR = i &0xff
NFADDR = (i >>9) &0xff
NFADDR = (i >>17) &0xff
NFADDR = (i >>25) &0xff
wait_idle()
for(j=0j <NAND_SECTOR_SIZEj++) {
*buf++ = (NFDATA &0xff)
}
}
NFCONF |= 0x800 /* chip disable */
return 0
}
文件6:sdram.c
/* 文件 sdram.c
* 作用:循环点 FS2410 开发板上的 D9、D10、D11、D12
* 四个发光二极管。
*/
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)
int main()
{
int i,j
while(1) {
for (i = 0i <4++i) {
GPFCON = 0x1<<(8+i*2)
GPFDAT = 0x0
// for delay
for(j=0j<50000++j)
}
}
}
文件7:nand.lds
SECTIONS {
first 0x00000000 : { head.o mem.o flash.o nand_read.o }
second 0x30000000 : AT(4096) { sdram.o }
}
文件8:Makefile
sdram:head.s flash.s mem.s sdram.c
arm-linux-gcc -c -o head.o head.s
arm-linux-gcc -c -o mem.o mem.s
arm-linux-gcc -c -o flash.o flash.s
arm-linux-gcc -c -o nand_read.o nand_read.c
arm-linux-gcc -c -o sdram.o sdram.c
arm-linux-ld -Tnand.lds head.o mem.o flash.o nand_read.o sdram.o -o sdram_tmp.o
arm-linux-objcopy -O binary -S sdram_tmp.o sdram
clean:
rm -f *.o
rm -f sdram
好了,你把这些文件拷下去,执行make命令就能生成可执行的二进制代码sdram,把sdram烧写到板子上就能运行了。祝你好运
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)