GNU ARM汇编--(二)汇编编译链接与运行
来源:互联网 发布:windows清理助手3 编辑:程序博客网 时间:2024/04/29 10:33
GNU ARM汇编--(二)汇编编译链接与运行
GNU的汇编器是GNU Tools的一部分,可以用来ARM的汇编语言源代码编译为二进制文件.关于GNU汇编器的介绍可以搜索《GNU Assembler Manual》.这里我们只是做一个简短的介绍,对GNU汇编器有一个大概的认识,同时通过两个例子了解一下GNU ARM汇编.
给出一个模板文件:
- .text ; Executable code follows
- _start: .global _start ; "_start" is required by the linker
- .global main ; "main" is our main program
- b main ; Start running the main program
- main: ; Entry to the function "main"
- ; Insert your code here
- mov pc,lr ; Return to the caller
- .end
.text ; Executable code follows_start: .global _start ; "_start" is required by the linker .global main ; "main" is our main program b main ; Start running the main programmain: ; Entry to the function "main"; Insert your code here mov pc,lr ; Return to the caller .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:
- .text
- .global _start
- _start:
- ldr r3, =0x53000000 @ WATCHDOG寄存器地址
- mov r4, #0x0
- str r4, [r3] @ 写入0,禁止WATCHDOG,否则CPU会不断重启
- ldr sp, =1024*2 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K
- @ nand flash中的代码在复位后会移到内部ram中,此ram只有4K
- bl _main @ 跳转到main函数
- halt_loop:
- b halt_loop
.text.global _start_start:ldr r3, =0x53000000 @ WATCHDOG寄存器地址mov r4, #0x0 str r4, [r3] @ 写入0,禁止WATCHDOG,否则CPU会不断重启ldr sp, =1024*2 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K @ nand flash中的代码在复位后会移到内部ram中,此ram只有4Kbl _main @ 跳转到main函数halt_loop:b halt_loop
beep.S
- .equ GPBCON, 0x56000010
- .equ GPBDAT, 0x56000014
- .global _main
- _main:
- ldr r0,=GPBCON
- ldr r1,=0x1
- str r1, [r0]
- loop:
- ldr r2,=GPBDAT
- ldr r1,=0x1
- str r1,[r2]
- bl delay
- ldr r2,=GPBDAT
- ldr r1,=0x0
- str r1,[r2]
- bl delay
- b loop
- delay:
- ldr r3,=0x4ffffff
- delay1:
- sub r3,r3,#1
- cmp r3,#0x0
- bne delay1
- mov pc,lr
- .end
.equ GPBCON, 0x56000010 .equ GPBDAT, 0x56000014 .global _main _main: ldr r0,=GPBCONldr r1,=0x1str r1, [r0]loop:ldr r2,=GPBDATldr r1,=0x1str r1,[r2]bl delayldr r2,=GPBDATldr r1,=0x0str r1,[r2]bl delayb loopdelay:ldr r3,=0x4ffffffdelay1:sub r3,r3,#1cmp r3,#0x0bne delay1mov pc,lr.end
beep.lds
- OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS{
- . = 0x33000000;
- .text : {
- *(.text)
- *(.rodata)
- }
- .data ALIGN(4): {
- *(.data)
- }
- .bss ALIGN(4): {
- *(.bss)
- }
- }
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{ . = 0x33000000; .text : { *(.text) *(.rodata) } .data ALIGN(4): { *(.data) } .bss ALIGN(4): { *(.bss) }}
makefile:
- CROSS = arm-linux-
- CFLAGS = -nostdlib
- beep.bin: start.S beep.S
- ${CROSS}gcc $(CFLAGS) -c -o start.o start.S
- ${CROSS}gcc $(CFLAGS) -c -o beep.o beep.S
- ${CROSS}ld -Tbeep.lds start.o beep.o -o beep.elf
- ${CROSS}objcopy -O binary -S beep.elf beep.bin
- rm -f *.o
- clean:
- rm -f *.elf *.o
- rm -f beep.bin
CROSS = arm-linux-CFLAGS = -nostdlibbeep.bin: start.S beep.S${CROSS}gcc $(CFLAGS) -c -o start.o start.S${CROSS}gcc $(CFLAGS) -c -o beep.o beep.S${CROSS}ld -Tbeep.lds start.o beep.o -o beep.elf${CROSS}objcopy -O binary -S beep.elf beep.binrm -f *.oclean:rm -f *.elf *.orm -f beep.bin
编译后将beep.bin文件烧写到dram中,就可以听到声音了.虽然可以运行了,但还是有两个疑问:
1.lds编译链接文件的写法和技巧 //后续要继续追
2.elf文件的格式 //elf格式是比较新的可执行文件格式,目前在很多OS上都是用这种格式.这个格式可以在有操作系统的情况下直接运行,但是对于裸机的情况,必须对elf文件 做objcopy处理 后续也要继续追
hello world的例子如下:
helloworld.S:
- .data
- msg: .asciz "hello, world\n"
- .text
- .align 2
- .global _start
- _start:
- ldr r1, =msg @ address
- mov r0, #1 @ stdout
- mov r2, #13 @ length
- swi #0x900004 @ sys_write
- mov r0, #0
- swi #0x900001 @ sys_exit
- .align 2
.datamsg: .asciz "hello, world\n".text .align 2 .global _start_start: ldr r1, =msg @ address mov r0, #1 @ stdout mov r2, #13 @ length swi #0x900004 @ sys_write mov r0, #0 swi #0x900001 @ sys_exit .align 2
makefile:
- all:
- arm-linux-as helloworld.S -o helloworld.o
- arm-linux-ld helloworld.o -o helloworld
all:arm-linux-as helloworld.S -o helloworld.oarm-linux-ld helloworld.o -o helloworld
将elf文件放到跑有linux的arm板子中,运行就输出hello world.也可以在ubuntu中qemu-arm helloworld模拟.
对比x86下同样用系统调用来输出hello world的程序:
- .data
- msg: .string "hello\n"
- 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
.datamsg: .string "hello\n"len = . - msg.text.global _start_start:nopmovl $len, %edxmovl $msg, %ecxmovl $1, %ebxmovl $4, %eaxint $0x80movl $0, %ebxmovl $1, %eaxint $0x80
它们有几点不同:
1.arm是用swi指令来进行软中断,陷入内核态来实现系统调用的.而x86是用int $0x80
2.x86的系统调用号是用eax寄存器表示的,是第一个参数.而arm的swi直接带有系统调用号,0x900004是0x900000+4,其中0x900000是base.
根据google,做了上面的总结,对GNU ARM汇编有了认识,并且对系统调用软中断,中断处理,uboot异常向量表等等有了探究的欲望,也对elf格式和编译链接有了兴趣,根据自己的方向和精力,后续对这些内容做一个或深或浅的学习.
- GNU ARM汇编--(二)汇编编译链接与运行
- GNU ARM汇编--(二)汇编编译链接与运行
- GNU ARM汇编--(二)汇编编译链接与运行
- GNU ARM汇编--(二)汇编编译链接与运行
- ARM标准汇编与GNU汇编
- ARM标准汇编与GNU汇编
- 转帖:ARM标准汇编与GNU汇编
- ARM标准汇编与GNU汇编
- GNU ARM汇编--(二十)总结
- GNU ARM汇编指令
- arm gnu 汇编语法
- GNU ARM汇编入门
- GNU ARM汇编入门
- GNU ARM汇编入门
- arm gnu 汇编语法
- GNU ARM 汇编指令
- GNU ARM 汇编指令
- GNU ARM汇编入门
- 从exe4j生成的exe中抽取jar文件
- common-lang的StringUtils使用
- GNU ARM汇编--(一)开篇
- 用正则表达式对网页进行有效内容抽取
- 怎样快速学习一门新技术
- GNU ARM汇编--(二)汇编编译链接与运行
- uva 620 Cellular Structure
- Cocos2d-x多场景切换生命周期
- 杭电1375 字数统计
- c#正则表达式
- cocos2dx android back键关闭游戏的方法
- 1248 - Every derived table must have its own alias (MYSQL错误)
- GNU ARM汇编--(三)ARM处理器的基本原则
- GNU ARM汇编--(四)中断汇编之非嵌套中断处理