微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > GNU ARM汇编--(二)汇编编译链接与运行

GNU ARM汇编--(二)汇编编译链接与运行

时间:11-26 来源:互联网 点击:
GNU的汇编器是GNU Tools的一部分,可以用来ARM的汇编语言源代码编译为二进制文件.关于GNU汇编器的介绍可以搜索《GNU Assembler Manual》.这里我们只是做一个简短的介绍,对GNU汇编器有一个大概的认识,同时通过两个例子了解一下GNU ARM汇编.

给出一个模板文件:

[cpp]view plaincopy

  1. .text;Executablecodefollows
  2. _start:.global_start;"_start"isrequiredbythelinker
  3. .globalmain;"main"isourmainprogram
  4. bmain;Startrunningthemainprogram
  5. main:;Entrytothefunction"main"
  6. ;Insertyourcodehere
  7. movpc,lr;Returntothecaller
  8. .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

  1. .text
  2. .global_start
  3. _start:
  4. ldrr3,=0x53000000@WATCHDOG寄存器地址
  5. movr4,#0x0
  6. strr4,[r3]@写入0,禁止WATCHDOG,否则CPU会不断重启
  7. ldrsp,=1024*2@设置堆栈,注意:不能大于4k,因为现在可用的内存只有4K
  8. @nandflash中的代码在复位后会移到内部ram中,此ram只有4K
  9. bl_main@跳转到main函数
  10. halt_loop:
  11. bhalt_loop


beep.S

[cpp]view plaincopy

  1. .equGPBCON,0x56000010
  2. .equGPBDAT,0x56000014
  3. .global_main
  4. _main:
  5. ldrr0,=GPBCON
  6. ldrr1,=0x1
  7. strr1,[r0]
  8. loop:
  9. ldrr2,=GPBDAT
  10. ldrr1,=0x1
  11. strr1,[r2]
  12. bldelay
  13. ldrr2,=GPBDAT
  14. ldrr1,=0x0
  15. strr1,[r2]
  16. bldelay
  17. bloop
  18. delay:
  19. ldrr3,=0x4ffffff
  20. delay1:
  21. subr3,r3,#1
  22. cmpr3,#0x0
  23. bnedelay1
  24. movpc,lr
  25. .end


beep.lds

[cpp]view plaincopy

  1. OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)
  4. SECTIONS{
  5. .=0x33000000;
  6. .text:{
  7. *(.text)
  8. *(.rodata)
  9. }
  10. .dataALIGN(4):{
  11. *(.data)
  12. }
  13. .bssALIGN(4):{
  14. *(.bss)
  15. }
  16. }


makefile:

[cpp]view plaincopy

  1. CROSS=arm-linux-
  2. CFLAGS=-nostdlib
  3. beep.bin:start.Sbeep.S
  4. ${CROSS}gcc$(CFLAGS)-c-ostart.ostart.S
  5. ${CROSS}gcc$(CFLAGS)-c-obeep.obeep.S
  6. ${CROSS}ld-Tbeep.ldsstart.obeep.o-obeep.elf
  7. ${CROSS}objcopy-Obinary-Sbeep.elfbeep.bin
  8. rm-f*.o
  9. clean:
  10. rm-f*.elf*.o
  11. rm-fbeep.bin


编译后将beep.bin文件烧写到dram中,就可以听到声音了.虽然可以运行了,但还是有两个疑问:

1.lds编译链接文件的写法和技巧 //后续要继续追

2.elf文件的格式 //elf格式是比较新的可执行文件格式,目前在很多OS上都是用这种格式.这个格式可以在有操作系统的情况下直接运行,但是对于裸机的情况,必须对elf文件 做objcopy处理 后续也要继续追

hello world的例子如下:

helloworld.S:

[cpp]view plaincopy

  1. .data
  2. msg:.asciz"hello,world"
  3. .text
  4. .align2
  5. .global_start
  6. _start:
  7. ldrr1,=msg@address
  8. movr0,#1@stdout
  9. movr2,#13@length
  10. swi#0x900004@sys_write
  11. movr0,#0
  12. swi#0x900001@sys_exit
  13. .align2


makefile:

[cpp]view plaincopy

  1. all:
  2. arm-linux-ashelloworld.S-ohelloworld.o
  3. arm-linux-ldhelloworld.o-ohelloworld


将elf文件放到跑有linux的arm板子中,运行就输出hello world.也可以在ubuntu中qemu-arm helloworld模拟.

对比x86下同样用系统调用来输出hello world的程序:

[cpp]view plaincopy

  1. .data
  2. msg:.string"hello"
  3. len=.-msg
  4. .text
  5. .global_start
  6. _start:
  7. nop
  8. movl$len,%edx
  9. movl$msg,%ecx
  10. movl$1,%ebx
  11. movl$4,%eax
  12. int$0x80
  13. movl$0,%ebx
  14. movl$1,%eax
  15. int$0x80


它们有几点不同:

1.arm是用swi指令来进行软中断,陷入内核态来实现系统调用的.而x86是用int $0x80

2.x86的系统调用号是用eax寄存器表

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top