S3C2440裸机编译不支持浮点运算问题记录

软件版本:练习程序

例程路径:F:\code\004

硬件平台:JZ2440(S3C2440)

/************************************************************************************************************************************/

知识普及:

(1)硬浮点(hard-float)

编译器将代码直接编译成硬件浮点协处理器(浮点运算单元FPU)能识别的指令,这些指令在执行的时候ARM核直接把它转给协处理器执行。FPU 通常有一套额外的寄存器来完成浮点参数传递和运算。使用实际的硬件浮点运算单元(FPU)会带来性能的提升。

(2)软浮点(soft-float)

编译器把浮点运算转成浮点运算的函数调用和库函数调用,没有FPU的指令调用,也没有浮点寄存器的参数传递。浮点参数的传递也是通过ARM寄存器或者堆栈完成。现在的Linux系统默认编译选择使用hard-float,如果系统没有任何浮点处理器单元,这就会产生非法指令和异常。因而一般的系统镜像都采用软浮点以兼容没有VFP的处理器。

用一句话总结,软浮点是通过浮点库去实现浮点运算的,效率低;硬浮点是通过浮点运算单元(FPU)来完成的,效率高。

/************************************************************************************************************************************/

编写JZ2440(S3C2440)UART驱动程序,初始化函数参考TI的DSP驱动写法,配置波特率寄存器使用了浮点运算

    uReg->ULCON=(0<<6)|(uartlink->parity<<3)|(uartlink->stopbit<<2)|(uartlink->databit<<0);
    uReg->UCON=(0<<10)|(1<<2)|(1<<0);//PCLK;TX/RX interrupt type:Interrupt request or polling mode
    uReg->UFCON=(0<<0);//disable fifo
    uReg->UMCON=(0<<4);
    uReg->UBRDIV=(unsigned int)(clock_MHz*1000000.f/(uartlink->baudrate*16)-1);

上述代码最后一行使用了浮点运算自行根据外设时钟PCLK计算波特率设置寄存器参数,编译时出现错误如下:

arm-linux-ld -Tlink.lds init.o uart.o start.o -o test.elf
uart.o(.text+0x1d8): In function `$a':
: undefined reference to `__mulsf3'
uart.o(.text+0x200): In function `$a':
: undefined reference to `__floatsisf'
uart.o(.text+0x224): In function `$a':
: undefined reference to `__floatsisf'
uart.o(.text+0x234): In function `$a':
: undefined reference to `__addsf3'
uart.o(.text+0x248): In function `$a':
: undefined reference to `__divsf3'
uart.o(.text+0x258): In function `$a':
: undefined reference to `__subsf3'
uart.o(.text+0x264): In function `$a':
: undefined reference to `__fixunssfsi'
Makefile:26: recipe for target 'test' failed
make: *** [test] Error 1


将uReg->UBRDIV=(unsigned int)(clock_MHz*1000000.f/(uartlink->baudrate*16)-1);改为

uReg->UBRDIV=26;则编译通过没有问题,查找资料发现是S3C2440没有浮点运算单元,只能使用软浮点,即由编译器的库文件支持,我使用的编译器没有浮点库,需要自己添加浮点库,并在编译器选项上添加库路径。

CFLAGS := -static -Werror -Iinclude -msoft -float -L/usr/local/arm/../libgcc.a

目前问题没有解决,留待以后完善

、、、、、、、、、、、、

根据韦东山裸机LCD视频,去库函数中查找  (一般来说编译器自带有很多库),进入工具链的目录: grep "__floatsisf" * -nr找到.a文件。

echo $PATH查看环境变量,得到编译器路径/usr/local/arm/gcc-3.4.5-glibc-2.3.6/bin,回到上层目录/usr/local/arm/gcc-3.4.5-glibc-2.3.6,使用 grep "__floatsisf" * -nr查找目录下含有__floatsisf标示的文件,得到:

Binary file arm-linux/lib/libm.a matches
Binary file arm-linux/lib/libm-2.3.6.so matches
Binary file arm-linux/lib/libc.a matches
Binary file arm-linux/lib/libgcc_s.so.1 matches
Binary file arm-linux/lib/libc-2.3.6.so matches
Binary file include/c++/3.4.5/arm-linux/bits/stdc++.h.gch/O0g matches
Binary file include/c++/3.4.5/arm-linux/bits/stdc++.h.gch/O2g matches
info/gccint.info:555: -- Runtime Function: float __floatsisf (int I)
Binary file info/gccint.info matches
Binary file lib/gcc/arm-linux/3.4.5/libgcc.a matches
将静态库拷贝到代码目录下,修改链接器命令:$(LD) -Tlink.lds $^ libgcc.a -o $@.elf,测试发现libgcc.a库包含浮点库函数,可以正常编译。

$(LD) -Tlink.lds $^ -L$(LIBPATH) -llibgcc -o $@.elf这个命令却不能找到库,只能拷贝到代码目录下链接

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常感谢您的提问。以下是一个简单的s3c2440 bootloader的C语言代码示例: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #define BOOTLOADER_SIZE 0x8000 #define KERNEL_LOAD_ADDRESS 0x30008000 int main(int argc, char **argv) { FILE *bootloader_file, *kernel_file; unsigned char *bootloader, *kernel; int bootloader_size, kernel_size; // Open bootloader file bootloader_file = fopen("bootloader.bin", "rb"); if (!bootloader_file) { printf("Error: Could not open bootloader file\n"); return 1; } // Read bootloader into memory fseek(bootloader_file, 0, SEEK_END); bootloader_size = ftell(bootloader_file); fseek(bootloader_file, 0, SEEK_SET); bootloader = (unsigned char *) malloc(bootloader_size); fread(bootloader, 1, bootloader_size, bootloader_file); fclose(bootloader_file); // Open kernel file kernel_file = fopen("kernel.bin", "rb"); if (!kernel_file) { printf("Error: Could not open kernel file\n"); return 1; } // Read kernel into memory fseek(kernel_file, 0, SEEK_END); kernel_size = ftell(kernel_file); fseek(kernel_file, 0, SEEK_SET); kernel = (unsigned char *) malloc(kernel_size); fread(kernel, 1, kernel_size, kernel_file); fclose(kernel_file); // Copy bootloader to memory memcpy((void *) 0, bootloader, bootloader_size); // Copy kernel to memory memcpy((void *) KERNEL_LOAD_ADDRESS, kernel, kernel_size); // Jump to kernel void (*kernel_entry)(void) = (void (*)(void)) KERNEL_LOAD_ADDRESS; kernel_entry(); return 0; } ``` 这个示例代码可以读取一个名为"bootloader.bin"的文件和一个名为"kernel.bin"的文件,将它们分别加载到内存的0地址和0x30008000地址处,然后跳转到0x30008000地址开始执行内核代码。 希望这个示例代码对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值