GNU ARM汇编--(二)汇编编译链接与运行
给出一个模板文件:
[cpp]view plaincopy
- .text;Executablecodefollows
- _start:.global_start;"_start"isrequiredbythelinker
- .globalmain;"main"isourmainprogram
- bmain;Startrunningthemainprogram
- main:;Entrytothefunction"main"
- ;Insertyourcodehere
- movpc,lr;Returntothecaller
- .end
一种汇编器是arm-elf-as,一种是arm-linux-as之类的,这两种汇编器是有细微区别.但是一般做开发,半导体厂商都会提供特定的编译器,用那个编译器应该是没错的,而且优化效果应该是最优的,毕竟是芯片公司提供的嘛.他们对体系架构最了解,很清楚的知道怎么去优化.而我们一般的开发者也可以了解处理器的体系架构和嵌入式系统的系统的特征来对汇编代码和c代码做优化.
编译过程:
arm-elf-as -marm7tdmi --gdwarf2 -o filename.o filename.s
-marm7tdmi是指定CPU,arm7tdmi是属于ARMv4T的,一般来说同是ARMv4T应该是兼容的.
--gdwarf2是表示包含debug信息.
链接过程:
arm-elf-ld -o filename.elf filename.o
和UNIX系统编程一样,我们可以根据上面的步骤写makefile,然后make一下.
具体ARM的指令集,伪指令就不写了,资料很多.
下面举两个ARM汇编的实例,一个是裸机下的蜂鸣器(简单的控制GPIO而已,比流水灯还简单),一个是ARM linux下的"hello world"(利用系统调用来实现的).
蜂鸣器的例子如下:
beep.lds beep.S Makefile start.S
start.S:
[cpp]view plaincopy
- .text
- .global_start
- _start:
- ldrr3,=0x53000000@WATCHDOG寄存器地址
- movr4,#0x0
- strr4,[r3]@写入0,禁止WATCHDOG,否则CPU会不断重启
- ldrsp,=1024*2@设置堆栈,注意:不能大于4k,因为现在可用的内存只有4K
- @nandflash中的代码在复位后会移到内部ram中,此ram只有4K
- bl_main@跳转到main函数
- halt_loop:
- bhalt_loop
beep.S
[cpp]view plaincopy
- .equGPBCON,0x56000010
- .equGPBDAT,0x56000014
- .global_main
- _main:
- ldrr0,=GPBCON
- ldrr1,=0x1
- strr1,[r0]
- loop:
- ldrr2,=GPBDAT
- ldrr1,=0x1
- strr1,[r2]
- bldelay
- ldrr2,=GPBDAT
- ldrr1,=0x0
- strr1,[r2]
- bldelay
- bloop
- delay:
- ldrr3,=0x4ffffff
- delay1:
- subr3,r3,#1
- cmpr3,#0x0
- bnedelay1
- movpc,lr
- .end
beep.lds
[cpp]view plaincopy
- OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS{
- .=0x33000000;
- .text:{
- *(.text)
- *(.rodata)
- }
- .dataALIGN(4):{
- *(.data)
- }
- .bssALIGN(4):{
- *(.bss)
- }
- }
makefile:
[cpp]view plaincopy
- CROSS=arm-linux-
- CFLAGS=-nostdlib
- beep.bin:start.Sbeep.S
- ${CROSS}gcc$(CFLAGS)-c-ostart.ostart.S
- ${CROSS}gcc$(CFLAGS)-c-obeep.obeep.S
- ${CROSS}ld-Tbeep.ldsstart.obeep.o-obeep.elf
- ${CROSS}objcopy-Obinary-Sbeep.elfbeep.bin
- rm-f*.o
- clean:
- rm-f*.elf*.o
- rm-fbeep.bin
编译后将beep.bin文件烧写到dram中,就可以听到声音了.虽然可以运行了,但还是有两个疑问:
1.lds编译链接文件的写法和技巧 //后续要继续追
2.elf文件的格式 //elf格式是比较新的可执行文件格式,目前在很多OS上都是用这种格式.这个格式可以在有操作系统的情况下直接运行,但是对于裸机的情况,必须对elf文件 做objcopy处理 后续也要继续追
hello world的例子如下:
helloworld.S:
[cpp]view plaincopy
- .data
- msg:.asciz"hello,world"
- .text
- .align2
- .global_start
- _start:
- ldrr1,=msg@address
- movr0,#1@stdout
- movr2,#13@length
- swi#0x900004@sys_write
- movr0,#0
- swi#0x900001@sys_exit
- .align2
makefile:
[cpp]view plaincopy
- all:
- arm-linux-ashelloworld.S-ohelloworld.o
- arm-linux-ldhelloworld.o-ohelloworld
将elf文件放到跑有linux的arm板子中,运行就输出hello world.也可以在ubuntu中qemu-arm helloworld模拟.
对比x86下同样用系统调用来输出hello world的程序:
[cpp]view plaincopy
- .data
- msg:.string"hello"
- len=.-msg
- .text
- .global_start
- _start:
- nop
- movl$len,%edx
- movl$msg,%ecx
- movl$1,%ebx
- movl$4,%eax
- int$0x80
- movl$0,%ebx
- movl$1,%eax
- int$0x80
它们有几点不同:
1.arm是用swi指令来进行软中断,陷入内核态来实现系统调用的.而x86是用int $0x80
2.x86的系统调用号是用eax寄存器表
ARM汇编汇编编译链接与运 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)
