《Linux设备驱动开发详解 A》一一3.6 工具链

简介:

本节书摘来华章计算机出版社《Linux设备驱动开发详解 A》一书中的第3章,第3.6节,作者:宋宝华 更多章节内容可以访问云栖社区“华章计算机”公众号查看。1

3.6 工具链

在Linux的编程中,通常使用GNU工具链编译Bootloader、内核和应用程序。 GNU组织维护了GCC、GDB、glibc、Binutils等,分别见于https://gcc.gnu.org/https://www.gnu.org/software/gdb/, https://www.gnu.org/software/libc/、https://www.gnu.org/software/binutils/
建立交叉工具链的过程相当烦琐,一般可以通过类似crosstool-ng这样的工具来做。crosstool-ng也采用了与内核相似的menuconfig配置方法。在官网http://www.crosstool-ng.org/上下载crosstool-ng的源代码并编译安装后,运行ct-ng menuconfig,会出现如图3.12的配置菜单。在里面我们可以选择目标机处理器型号,支持的内核版本号等。
image

图3.12  crosstool-ng的配置菜单
当然,也可以直接下载第三方编译好的、开放的、针对目标处理器的交叉工具链,如在http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/上可以下载针对ARM、MIPS、高通 Hexagon、Altera Nios II、Intel、AMD64等处理器的工具链,在http://www.linaro.org/downloads/可以下载针对ARM的工具链。
目前,在ARM Linux的开发中,人们趋向于使用Linaro(http://www.linaro.org/)工具链团队维护的ARM 工具链,它以每月一次的形式发布新的版本,编译好的可执行文件可从网址http://www.linaro.org/downloads/下载。Linaro是ARM Linux领域中最著名最具技术成就的开源组织,其会员包括ARM、Broadcom、Samsung、TI、Qualcomm等,国内的海思、中兴、全志和中国台湾的MediaTek也是它的会员。
一个典型的ARM Linux工具链包含arm-linux-gnueabihf-gcc(后续工具省略前缀)、strip、gcc、objdump、ld、gprof、nm、readelf、addr2line等。用strip 可以删除可执行文件中的符号表和调试信息等来实现缩减程序体积的目的。gprof在编译过程中在函数入口处插入计数器以收集每个函数的被调用情况和被调用次数,检查程序计数器并在分析时找出与程序计数器对应的函数来统计函数占用的时间。objdump是反汇编工具。nm则用于显示关于对象文件、可执行文件以及对象文件库里的符号信息。其中,前缀中的“hf”显示该工具链是完全的硬浮点,由于目前主流的ARM芯片都自带VFP或者NEON等浮点处理单元(FPU),所以对硬浮点的需求就更加强烈。Linux的浮点处理可以采用完全软浮点,也可以采用与软浮点兼容,但是使用FPU硬件的softfp,以及完全硬浮点。具体的ABI(Application Binary Interface,应用程序二进制接口)通过-mfloat-abi=参数指定,3种情况下的参数分别是-mfloat-abi=soft/softfp/hard。
在以前,主流的工具链采用“与软浮点兼容,但是使用FPU硬件的softfp”。 softfp使用了硬件的FPU,但是函数的参数仍然使用整型寄存器来传递,完全硬浮点则直接使用FPU的寄存器传递参数。
下面一段程序:

float mul(float a, float b)
{
        return a * b;
}
void main(void)
{
        printf("1.1 * 2.3 = %f\n", mul(1.1, 2.3));
}

对其使用arm-linux-gnueabihf-gcc编译并反汇编的结果是:
000 08394 :

8394:     b480        push  {r7}
     8396:     b083        sub  sp, #12
     8398:     af00        add  r7, sp, #0
     839a:     ed87 0a01   vstr  s0, [r7, #4](null)
     839e:     edc7 0a00   vstr  s1, [r7]
     83a2:     ed97 7a01   vldr  s14, [r7, #4](null)
     83a6:     edd7 7a00   vldr  s15, [r7]
     83aa:     ee67 7a27   vmul.f32  s15, s14, s15
     83ae:     eeb0 0a67   vmov.f32  s0, s15
     83b2:     f107 070c   add.w  r7, r7, #12
     83b6:     46bd        mov  sp, r7
     83b8:     bc80        pop  {r7}
     83ba:     4770        bx    lr

0000 83bc <main>:
     83bc:     b580        push  {r7, lr}
     83be:     af00        add  r7, sp, #0
     83c0:     ed9f 0a09   vldr  s0, [pc, #36](null)  ; 83e8 <main+0x2c>
     83c4:     eddf 0a09   vldr  s1, [pc, #36](null)  ; 83ec <main+0x30>
     83c8:     f7ff ffe4   b8394 <mul>
     83cc:     eef0 7a40   vmov.f32  s15, s0
     83d0:     eeb7 7ae7   vcvt.f64.f32  d7, s15
     83d4:     f248 4044   movw  r0, #33860  ; 0x8444
     83d8:     f2c0 0000   movt  r0, #0
     83dc:     ec53 2b17   vmov  r2, r3, d7
     83e0:     f7ff ef82   blx  82e8 <_init+0x20>
     83e4:     bd80        pop  {r7, pc}
     83e6:     bf00        nop
而使用没有“hf”前缀的arm-linux-gnueabi-gcc编译并反汇编的结果则为
000 0838c <mul>:
     838c:     b480        push  {r7}
     838e:     b083        sub  sp, #12
     8390:     af00        add  r7, sp, #0
     8392:     6078        str  r0, [r7, #4]
     8394:     6039        str  r1, [r7, #0]
     8396:     ed97 7a01   vldr  s14, [r7, #4](null)
     839a:     edd7 7a00   vldr  s15, [r7]
     839e:     ee67 7a27   vmul.f32  s15, s14, s15
     83a2:     ee17 3a90   vmov  r3, s15
     83a6:     4618        mov  r0, r3
     83a8:     f107 070c   add.w  r7, r7, #12
     83ac:     46bd        mov  sp, r7
     83ae:     bc80        pop  {r7}
     83b0:     4770        bx    lr
     83b2:     bf00        nop

000 083b4 <main>:
     83b4:     b580        push  {r7, lr}
     83b6:     af00        add  r7, sp, #0
     83b8:     4808        ldr  r0, [pc, #32]  ; (83dc <main+0x28>)
     83ba:     4909        ldr  r1, [pc, #36]  ; (83e0 <main+0x2c>)
     83bc:     f7ff ffe6   bl  838c <mul>
     83c0:     ee07 0a90   vmov  s15, r0
     83c4:     eeb7 7ae7   vcvt.f64.f32  d7, s15
     83c8:     f248 4038   movwr0, #33848    ; 0x8438
     83cc:     f2c0 0000   movtr0, #0
     83d0:     ec53 2b17   vmovr2, r3, d7
     83d4:     f7ff ef84   blx  82e0 <_init+0x20>
     83d8:     bd80        pop  {r7, pc}
     83da:     bf00        nop

关注其中加粗的行,可以看出前面的汇编使用s0和s1传递参数,后者则仍然使用ARM的r0和r1。测试显示一个含有浮点运算的程序若使用hard ABI会比softfp ABI快5%~40%,如果浮点负载重,结果可能会快200%以上。

相关文章
|
5天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
24 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
1月前
|
Linux C语言 SoC
嵌入式linux总线设备驱动模型分析
嵌入式linux总线设备驱动模型分析
32 1
|
21天前
|
Linux API C语言
FFmpeg开发笔记(一)搭建Linux系统的开发环境
本文指导初学者如何在Linux上搭建FFmpeg开发环境。首先,由于FFmpeg依赖第三方库,可以免去编译源码的复杂过程,直接安装预编译的FFmpeg动态库。推荐网站<https://github.com/BtbN/FFmpeg-Builds/releases>提供适用于不同系统的FFmpeg包。但在安装前,需确保系统有不低于2.22版本的glibc库。详细步骤包括下载glibc-2.23源码,配置、编译和安装。接着,下载Linux版FFmpeg安装包,解压至/usr/local/ffmpeg,并设置环境变量。最后编写和编译简单的C或C++测试程序验证FFmpeg环境是否正确配置。
37 8
FFmpeg开发笔记(一)搭建Linux系统的开发环境
|
1月前
|
算法 Linux 调度
根基已筑!Anolis OS 23.1 预览版本搭载 Linux 6.6 内核和工具链升级完成
Anolis OS 23.1 对软件包的选择和组合进行了重新规划与决策,满足更为广泛的应用场景需求。
|
1月前
|
存储 缓存 Linux
探秘Linux块设备驱动程序:成为内核开发大师的第一步
探秘Linux块设备驱动程序:成为内核开发大师的第一步
93 0
|
1月前
|
Linux
linux驱动开发-点亮第一个led灯
linux驱动开发-点亮第一个led灯
23 0
|
1月前
|
网络协议 Java Linux
Java 开发常用的 Linux 命令知识积累
Java 开发常用的 Linux 命令知识积累
38 0
|
1月前
|
Linux C语言 开发者
Linux嵌入式系统之交叉编译中构建交叉编译工具链
Linux嵌入式系统之交叉编译中构建交叉编译工具链
14 0
|
1月前
|
Linux
Linux内核中USB设备驱动实现
Linux内核中USB设备驱动实现
25 0
|
1月前
|
网络协议 Ubuntu Linux
「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接
「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接
131 0