历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2021年09月16日 | GNU ARM交叉汇编环境的搭建与测试

2021-09-16 来源:eefocus

对ARM进行裸机开发时,汇编是必不可少的,因为C语言无法直接操作CPU的内置寄存器,也就无法完成很多硬件初始化的功能,如内存控制器的初始化。


市面上大多数讲解ARM汇编开发的书籍都把ADS作为开发环境,因此使用的汇编语言也就是ARMASM,开发平台也限制到了Windows。然而在嵌入式领域,Linux作为开发环境更加普及,那么如何在Linux下进行ARM的汇编程序设计呢?


其实,Linux平台上早就有了支持ARM的汇编器,那就是著名的binutils软件包,它包含了汇编、链接、二进制操作等所有的ARM汇编环境。


1 binutils简介

binutils是支持Unix类系统汇编与链接开源软件包,提供汇编、链接等二进制文件操作工具。其官方主页是: http://www.gnu.org/software/binutils。著名的GCC编译器本身并不提供汇编和链接功能,而是依赖于这个binutils才能完成高级语言的编译、汇编、链接过程。它提供的工具包括:

* GNU链接器ld

* GNU汇编器as

* objcopy 转换二进制格式

* ar 对象文件打包管理

* c++filt C++符号名字反mangling

* nm 打印二进制文件里的符号信息

* readelf 读取分析elf格式文件信息

* ranlib 产生archive包的索引

* size 列出二进制文件的大小

* objdump 打印二进制文件信息

* strip 去除二进制文件中的符号信息

* strings 打印二进制文件中的可打印符号

* dlltool 为构建和使用DLL创建文件

* gprof 显示配置信息

* addr2line 把内存地址对应到源文件中的行号(用于调试)

* nlmconv 转为对象代码为NLM

* gold 只用于ELF格式的新生代连接器(尚处于测试阶段)


对于ARM汇编程序开发,as,ld,objcopy是最基本的工具。


2 binutils安装

对于ARM汇编来说,最常见的就是开发平台是基于X86的LinuxPC机器,而运行平台则是基于ARM的嵌入式硬件平台。这就需要一个能生成ARM机器码的交叉汇编器和连接器。binutils自然能够满足这个小小的要求,只是需要进行编译安装就可以了。


2.1 准备binutils源码

去其官网下载最新的源码包,截至目前(2016年12月12日)最新的版本为2.27,下载得到的文件名为: binutils-2.27.tar.bz2。

解压


tar -jxvf binutils-2.27.tar.bz2


得到binutils-2.27文件夹。


不建议直接在binutils-2.27这个源文件目录下直接配置编译,以免造成混乱。为此,新建一个空目录build-binutils,用于编译。


2.2 配置,编译,安装

进入build-binutils目录,执行如下配置命令:


../binutils-2.27/configure --prefix=/home/smstong/ARM --target=arm-linux-gnueabihf


上面指定了binutils的安装目录与目标平台,运行完成会在当前目录下生成Makefile。执行make,make install完成安装


make

make install


与GCC不同,binutils的配置、编译、安装非常简单,很少会出错。安装完成后会产生如下目录结构:


ARM

├── arm-linux-gnueabihf

│   ├── bin

│   │   ├── ar

│   │   ├── as

│   │   ├── ld

│   │   ├── ld.bfd

│   │   ├── nm

│   │   ├── objcopy

│   │   ├── objdump

│   │   ├── ranlib

│   │   ├── readelf

│   │   └── strip

│   └── lib

│       └── ldscripts

│         

├── bin

│   ├── arm-linux-gnueabihf-addr2line

│   ├── arm-linux-gnueabihf-ar

│   ├── arm-linux-gnueabihf-as

│   ├── arm-linux-gnueabihf-c++filt

│   ├── arm-linux-gnueabihf-elfedit

│   ├── arm-linux-gnueabihf-gprof

│   ├── arm-linux-gnueabihf-ld

│   ├── arm-linux-gnueabihf-ld.bfd

│   ├── arm-linux-gnueabihf-nm

│   ├── arm-linux-gnueabihf-objcopy

│   ├── arm-linux-gnueabihf-objdump

│   ├── arm-linux-gnueabihf-ranlib

│   ├── arm-linux-gnueabihf-readelf

│   ├── arm-linux-gnueabihf-size

│   ├── arm-linux-gnueabihf-strings

│   └── arm-linux-gnueabihf-strip

└── share

    └── man

        └── man1


其中ARM/bin和ARM/arm-linux-gnueabihf/bin目录下存放的就是as,ld等二进制工具。实际上这两个目录里的文件是完全一样的,只是名字不同而已。


[smstong@centos192 ~]$ ls ARM/arm-linux-gnueabihf/bin -i

54202 ar  54228 ld      54209 nm       54201 objdump  54207 readelf

54218 as  54228 ld.bfd  54205 objcopy  54204 ranlib   54210 strip

[smstong@centos192 ~]$ ls ARM/bin/ -i

54206 arm-linux-gnueabihf-addr2line  54209 arm-linux-gnueabihf-nm

54202 arm-linux-gnueabihf-ar         54205 arm-linux-gnueabihf-objcopy

54218 arm-linux-gnueabihf-as         54201 arm-linux-gnueabihf-objdump

54211 arm-linux-gnueabihf-c++filt    54204 arm-linux-gnueabihf-ranlib

54208 arm-linux-gnueabihf-elfedit    54207 arm-linux-gnueabihf-readelf

54222 arm-linux-gnueabihf-gprof      54200 arm-linux-gnueabihf-size

54228 arm-linux-gnueabihf-ld         54203 arm-linux-gnueabihf-strings

54228 arm-linux-gnueabihf-ld.bfd     54210 arm-linux-gnueabihf-strip


可见,ARM/arm-linux-gnueabihf/bin/as 和 ARM/bin/arm-linux-gnueabihf-as共享同一个索引节点号,是彼此的硬链接。为了与开发主机上的本地binutils相区别,建议使用长文件名的那个硬链接。为此,把它们加入可执行路径:


export PATH=/home/smstong/ARM/bin:$PATH


这样我们就可以直接使用arm-linux-gnueabihf-as命令了。


3 目标机器是裸机下的汇编程序开发

下面直接给出一个具体的例子。


3.1 实验环境

本次实验的运行平台为TQ2440开发板。从Norflash启动硬件,并且Norflash中已经预装了u-boot,且u-boot支持通过tftp协议下载程序到指定内存地址执行。


开发主机安装运行了tftp服务器,文件根目录为/var/lib/tftpboot,编译生成的二进制文件led.bin被复制到此目录下。


这就是说,测试程序执行前,u-boot已经完成了硬件平台的基本初始化:SDRAM可用,堆栈环境已经设置,MMU未启用,所以虚拟地址和物理地址完全相同。


这样我们的测试程序就可以做的非常简单。


本次实验的结果是熄灭底板上的LED1。因为u-boot启动后,LED1被自动点亮,我们的测试程序用来熄灭它。


3.2 源码

源文件 led.s。

我们都知道,GNU的X86汇编指令与Intel文档提供的标准格式相差很大,而这种情况在ARM汇编中不再存在,

GNU ARM AS支持ARM公司提供的标准汇编指令格式,而且扩展了一些特有的伪指令。


.equ GPBCON, 0x56000010

.equ GPBDAT, 0x56000014

.equ GPBUP,  0x56000018

.equ UBOOT,  0x00000000


.section .text

    .global _start

_start:

    ldr r0, =GPBCON

    ldr r1, [r0]

    bic r1, r1, #0xC00

    orr r1, r1, #0x400

    str r1, [r0]


    ldr r0, =GPBUP

    ldr r1, [r0]

    bic r1, r1, #0x20

    str r1, [r0]


    ldr r0, =GPBDAT

    ldr r1, [r0]

    orr r1, r1, #0x20

    str r1, [r0]


    b UBOOT /* 跳转回Norflash,重新进入u-boot */


.end


链接脚文件 led.lds:


ENTRY(_start)


SECTIONS {

    . = 0x30000000;

    .text : {       /* text and : must be seperated by space */

        *(.text)

        *(.rodata)

    }

    .data ALIGN(4): {

        *(.data)

    }

    .bss ALIGN(4): {

        *(.bss)

    }

}


Makefile文件:


AS = arm-linux-gnueabihf-as

LD = arm-linux-gnueabihf-ld

OBJCPY = arm-linux-gnueabihf-objcopy


all: led.bin

    sudo cp led.bin /var/lib/tftpboot/


led.bin: led

    $(OBJCPY) -O binary $< $@


led: led.o

    $(LD)  --script=led.lds -o $@ $<


led.o: led.s

    $(AS) -o $@ $<


.PHONY: clean

clean:

    rm *.o led led.bin


3.3 编译链接说明

链接时需要指定代码段的起始内存地址为0x30000000,以满足TQ2440开发板的内存布局,这通过链接脚本led.lds来完成。


链接器生产的可执行程序led为elf格式,这是Linux操作系统下的标准可执行格式,需要操作系统提供的加载器才能加载执行,在开发板裸机上不能直接运行,这就需要通过objcopy工具把elf格式转化为单纯的二进制格式led.bin。

整个转换汇编链接过程:


led.s---(汇编器as)-->led.o---(连接器ld)-->led---(objcopy工具)--->led.bin


3.4 下载到开发板执行

#####    Boot for Nor Flash Main Menu   #####

#####     EmbedSky USB download mode     #####


[1] Download u-boot or other bootloader to Nand Flash

[2] Download Eboot (eboot.nb0) to Nand Flash

[3] Download Linux Kernel (zImage.bin) to Nand Flash

[4] Download WinCE NK.bin to Nand Flash

[5] Download CRAMFS image to Nand Flash

[6] Download YAFFS image (root.bin) to Nand Flash

[7] Download Program (uCOS-II or TQ2440_Test) to SDRAM and Run it

[8] Boot the system

[9] Format the Nand Flash

[0] Set the boot parameters

[a] Download User Program (eg: uCOS-II or TQ2440_Test)

[b] Download LOGO Picture (.bin) to Nand  Flash

[l] Set LCD Parameters

[n] Enter TFTP download mode menu

[o] Download u-boot to Nor Flash

[r] Reboot u-boot

[t] Test Linux Image (zImage)

[q] quit from menu

Enter your selection: n


#####    Boot for Nor Flash Main Menu   #####

#####     EmbedSky TFTP download mode     #####


[1] Download u-boot.bin to Nand Flash

[2] Download Eboot (eboot.nb0) to Nand Flash

[3] Download Linux Kernel (zImage.bin) to Nand Flash

[4] Download WinCE NK.bin to Nand Flash

[5] Set TFTP parameters(PC IP,TQ2440 IP,Mask IP...)

[6] Download YAFFS image (root.bin) to Nand Flash

[7] Download Program (uCOS-II or TQ2440_Test) to SDRAM and Run it

[8] Boot the system

[9] Format the Nand Flash

[0] Set the boot parameters

[a] Download User Program (eg: uCOS-II or TQ2440_Test)

[b] Download LOGO Picture (.bin) to Nand  Flash

[l] Set LCD Parameters

[o] Download u-boot to Nor Flash

[p] Test network (TQ2440 Ping PC's IP)

[r] Reboot u-boot

[t] Test Linux Image (zImage)

[q] Return main Menu

Enter your selection: 7

Enter downloads to SDRAM address:

0x30000000

Enter program name:

led.bin

tftp 0x30000000 led.bin

dm9000 i/o: 0x20000300, id: 0x90000a46

MAC: 0a:1b:2c:3d:4e:5f

TFTP from server 172.16.35.188; our IP address is 172.16.35.189

Filename 'led.bin'.

Load address: 0x30000000

Loading: #

done

Bytes transferred = 80 (50 hex)

## Starting application at 0x30000000 ...


可以看到开发板上的LED1灯已经被熄灭了。


4 目标机器是Linux系统下的汇编程序开发

汇编程序当然也适合在Linux系统下运行,而且有了OS的支持,汇编程序可以通过系统调用的方式非常爽的使用OS提供的API。下面给出一个hello world的例子。


4.1 源码

源码非常简单hello.s:


.section .data

msg:

    .asciz "hello,GNU ARM ASMn"


.section .text

    .global _start

_start:

    mov r0,#1       /* file fd */

    ldr r1, =msg

    mov r2,#18

    swi #0x900004   /* sys_write(fd,msg,len) */


    mov r0,#0

    swi #0x900001   /* sys_exit(code) */


Makefile:


AS = arm-linux-gnueabihf-as

LD = arm-linux-gnueabihf-ld

all: hello

    sudo cp hello /var/lib/tftpboot/

hello: hello.o

    $(LD) -o $@ $<


hello.o: hello.s

    $(AS) -o $@ $<


.PHONY: clean

clean:

    rm *.o hello


4.2 编译链接说明

默认情况下链接器会把_start作为入口,代码段基地址默认为0x00010074。因为开发板运行的是Linux系统,所以会把这个虚拟地址转换为可用的物理地址。


通过swi软中断方式调用Linux内核API,很轻易就实现了打印字符串的功能。在OS下开发程序是多么幸福的事情!


4.3 系统调用还是标准C库?

汇编程序有两种使用系统API的方式,一是上面例子中的直接使用swi陷入内核;二是调用标准C库函数。个人建议还是第一种方法更好,因为第二种方法存在如下问题:


开发环境下,目标机器的标准C库不一定存在,例如我们目前的环境,由于还没有编译安装标准C库;这样交叉链接无法完成链接任务。

也许有人说,使用标准C库会使得程序具有更强的可移植性。可是别忘了,我们开发的是汇编程序,汇编程序天生就不具有可移植性!!!

推荐阅读

史海拾趣

EMC Component Group公司的发展小趣事

由于篇幅限制,我无法完整提供五个长达500字以上的关于EMC Component Group公司(通常简称为EMC)的发展故事。然而,我可以概述五个与公司发展历程相关的重要事件或阶段,每个事件以精简的方式描述。

  1. 成立与初期发展

1979年,Richard Egan和Roger Marino两位创始人决定不再为别人打工,共同创立了EMC公司。最初,公司的业务并不专注于存储,而是销售办公家具。随着对市场的深入了解,他们发现了内存市场的商机,开始成为英特尔的渠道代理,为小型机提供内存。这一转变为EMC积累了第一桶金,也为公司未来的发展奠定了重要基础。

  1. 业务转型与内存业务的发展

在一位客服的建议下,EMC开始研发并销售Prime Computer的兼容内存。这些产品以同类产品一半的价格提供更高的性能,迅速在市场上获得认可。随着内存业务的不断发展,EMC逐渐成为了该领域的领导者。

  1. 存储解决方案的推出

进入21世纪,EMC开始将业务重心转向存储解决方案。2002年,公司推出了Centera,这是世界上第一个内容寻址存储(CAS)解决方案。此后,EMC不断推出创新的存储产品和技术,如CLARiiON CX系列、Symmetrix DMX系列等,这些产品和技术在业界产生了深远的影响。

  1. 云存储与软件定义技术的探索

随着云计算和软件定义技术的兴起,EMC也开始了在这一领域的探索。2014年,公司收购了全闪存初创公司,并试图将自己变成灵活的云供应商。此外,EMC还通过升级高端和低端产品线扩展了其产品线,并推出了针对闪存的基础特性进行开发和设计的XtremIO产品。

  1. 与Dell的合并

在EMC的发展历程中,一个重要的里程碑是与Dell的合并。这次合并不仅加强了EMC在存储和云计算领域的实力,也为其未来的发展提供了更广阔的空间。合并后,EMC成为了Dell Technologies的一部分,继续为全球客户提供创新的存储和云计算解决方案。

Esico-Triton公司的发展小趣事

近年来,Esico-Triton越来越重视企业的可持续发展和社会责任。公司开始着手研发更加环保的电子产品,减少有害物质的使用,推动循环经济的发展。此外,Esico-Triton还积极参与社会公益活动,支持教育事业和环境保护项目,以实际行动回馈社会。这些举措不仅提升了公司的品牌形象,也为电子行业的可持续发展树立了典范。

远阳(FLYOUNG)公司的发展小趣事

人才是企业发展的根本。国光新业深知这一点,因此始终注重人才的引进与培养。公司推出了“国新力”人才计划专项,构建了一支优秀人才梯队。目前,企业的技术团队中科技人员占比超过30%,其中拥有工程师以上职称的比例更是超过六成。这些高素质的人才为公司的技术创新与产品研发提供了源源不断的动力。

汇顶科技(GOODiX)公司的发展小趣事

国光新业在深耕国内市场的同时,也积极拓展海外市场。公司的电容器产品凭借其优异的性能与可靠的质量,赢得了国内外众多客户的信赖与好评。随着品牌影响力的不断提升,国光新业已成为电子元器件行业中的佼佼者。未来,公司将继续坚持创新驱动发展战略,不断提升产品与服务的品质与竞争力,致力于成为具有国际竞争力的电子元器件供应商。

屹晶微(EG)公司的发展小趣事

屹晶微的创始人黄米龙,原本在发电厂从事电气运营工作长达八年。这段经历让他对电子领域有了深入的了解和浓厚的兴趣。然而,他并没有满足于现状,而是看到了中国芯片产业的巨大潜力和发展空间。于是,在2007年,他毅然决定从发电厂辞职,利用自己的积蓄和借来的资金,在台州创立了屹晶微电子有限公司。

在创立初期,屹晶微面临着资金短缺、技术落后和市场竞争激烈的困境。但黄米龙凭借对电子行业的深刻理解和坚定的信念,带领团队克服了种种困难。他们不断引进先进技术和设备,加强研发力量,提升产品质量。经过几年的努力,屹晶微逐渐在芯片设计领域崭露头角,并成功推出了多款具有自主知识产权的芯片产品。

Altech公司的发展小趣事

凭借在铝合金导体领域的卓越成就和持续创新,Altech公司成功获得了国家级高新技术企业的认定。这一荣誉不仅是对公司技术实力和创新能力的肯定,也为公司未来的发展提供了有力的支持。作为国家级高新技术企业,Altech公司将继续加大研发投入,推动技术创新,为电子行业的发展做出更大的贡献。

问答坊 | AI 解惑

CMM与CAM一体化技术在汽车车身设计中的应用

汽车产业是我国重点支柱产业,但目前国内各汽车生产厂的车身造型设计基本还停留在传统手工制作上,不仅制作精度低,耗费大量的人力和工时,也制约了汽车工业自主开发的进程,所以在汽车设计模型制作过程中将三维数学主模型直接编程加工并通过数字照 ...…

查看全部问答>

“安防靠狗”,农村市场大有可为!

“安防靠狗”的说法深有体会,家里那边村子里,基本人人都有条狗,动不动就是藏獒、动不动就是黑背,搞得邻里关系整得日益疏远,谁也不想给狗当午餐不是? 但不可否认的是,农村安防确实是一个非常大的市场,但是如果没有国家实质性投入的话,这 ...…

查看全部问答>

帮朋友发个QQ群,招人,嘿嘿

这个群建立以来一直只有几个人,现在我来帮忙招人进去。 29521470…

查看全部问答>

error C2061: syntax error : identifier 'SHFILEINFOW'

C:\\Program Files\\Windows CE Tools\\wce600\\ProgWinCE_SDK\\Include\\Armv4i\\shellapi.h(321) : error C2061: syntax error : identifier \'SHFILEINFOW\' 1>D:\\Program Files\\Microsoft Visual Studio 8\\VC\\atlmfc\\include\\afxv_w32.h ...…

查看全部问答>

求助RTX环境下串口通信的问题

小弟最近开始学习Ardence RTX,有很多不懂得地方,下面是一个基于serialAPI.h开发驱动的RTX通信串口测试程序。主线程是读数据,次线程是写数据。经过两次测试: 1.在单台计算机上用串口线连接COM1和COM2,并在RTX环境下将其打开,将下面次线程中写 ...…

查看全部问答>

请问各位大虾,有熟悉lwip的吗? 问个在inet.c文件中有个inet_chksum_pseudo()的函数相关问题。

函数原型如下: /* inet_chksum_pseudo: * * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. */ u16_t inet_chksum_pseudo(struct pbuf *p,        struct ip_addr *src, struct i ...…

查看全部问答>

msp430 PWM输出问题

比如占空比为20%,pwm输出管脚不能使用定时器,所以我用中断定时时间来实现输出,定时时间到置管脚高电平或者低电平,现在我想问的是:我的pwm的周期怎么定呢 …

查看全部问答>

SJF烧写的问题,请前辈赐教

我的笔记本上本身带有并口,并且安装了打印程序,可以执行打印任务。为了烧写WINCE,我安装了GIVEIO,安装没有抱错,在设备管理器里 可以看到:端口(COM和LPT)->ECP打印机(LPT1),giveio(COM6). 应该说,不会出现问题,可是当我烧写的时候,出现错 ...…

查看全部问答>

在Microsoft Visual Studio 2005下编译的程序怎么不能在WINCE4.2下运行?

在WINCE5下都可以正常运行,到WINCE4.2下就提示不是有效的WINDOW CE应用程序了,有什么办法可以解决啊?…

查看全部问答>

ST中TB中断只能进入一次

@interrupt void TB_INIT(void){    PADR=0;    return;}void main(void){    PADDR=0x0F;    PAOR=0x0F;    LTCSR=0x ...…

查看全部问答>