ILD

arm除法指令
作者:Herbert Yuan 邮箱:yuanjp89@163.com
发布时间:2017-11-7 站点:Inside Linux Development

ARM直到ARMv7才支持除法指令,支持情况如下:

Support for the SDIV/UDIV instructions is mandatory in ARMv7-M and for the Thumb instruction set in ARMv7-R. It is optional for the ARM instruction set in ARMv7-R. It is optional in ARMv7-A and, if supported, may be in the Thumb instruction set only or in both Thumb and ARM. In ARMv7-A with the Virtualization Extensions, it is mandatory in Thumb and ARM.


没有除法指令的架构,编译器通过实现一个除法函数,将除法编译为使用该函数实现,编译bare metal系统时,需要链接-lgcc。


但是,如果除法操作数全部是常数的话,编译器可以预先计算出结果,从而绕过除法指令或者调用除法函数,如下:

1
2
3
4
5
6
7
#define PCLK_HZ         (67*1000*1000)
#define WATCHDOG_TIMER  5
#define prescaler       255
#define division_factor 128
 
    count = PCLK_HZ / prescaler / division_factor * 
                WATCHDOG_TIMER;


如果某个操作数为变量,就需要使用运行在目标机器的除法实现了,如改成如下:

1
2
3
4
5
6
7
8
#define PCLK_HZ         (67*1000*1000)
#define WATCHDOG_TIMER  5
#define prescaler       255
#define division_factor 128
    int prescaler_2 = 255;
 
    count = PCLK_HZ / (1 + prescaler_2) / division_factor * 
                WATCHDOG_TIMER;


没链接gcc库,将报错:

1
2
3
4
5
/work/toolchain/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-ld -T bare.lds -o int_elf start.o init.o
init.o: In function `start_watchdog':
/work/code/s3c2440/watchdog_timer/init.c:130: undefined reference to `__aeabi_idiv'
Makefile:3: recipe for target 'all' failed
make: *** [all] Error 1


修改编译选项:

1
$(LD) -T bare.lds -o int_elf start.o init.o /work/toolchain/arm-unknown-linux-gnueabi/lib/gcc/arm-unknown-linux-gnueabi/6.3.0/libgcc.a

由于bare.lds未指定任何search dir,所以这里使用libgcc.a的绝对路径。


同时需要添加一个raise()函数,gcc库会调用该由用户实现的外部raise函数。

1
2
3
void raise()
{
}


可正常编译和烧录后运行正常,libgcc.a有22M之多,但是编译出来的bin很小,链接器只会链接静态库中用的模块,但是其是基于模块,而不是函数。


参考:

【1】Divide and Conquer. https://community.arm.com/processors/b/blog/posts/divide-and-conquer


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.