GNU ARM汇编语法入门
GNU ARM汇编语法入门
GNU汇编器是GNU工具套件之一,其作用是把ARM汇编源代码转换成二进制对象文件。该汇编器的详细资料请参见GNU Assembler Manual,本文是该手册的摘要。
例子和模板文件
Examples 文件夹和他的子文件夹包含很多汇编语言程序例子,你可以学习它们。
Examples 有一个子文件是templates。在你开始写程序之前,强烈建议你使用那个文件夹提供的模板做为起点。特别的,template.s 文件应该在你所有的ARM程序中使用。在去除大部分该文件的注释后,内容如下:
.text ; 以下为可执行代码
_start: .global _start ; "_start" 是连接器所必须的
.global main ; "main" 是主程序
b main ; 跳转到主程序
main: ; "main" 程序入口
; 这里添加你自己的程序
mov pc,lr ; 返回
.end
调用汇编器
你可以使用arm-elf-as工具来编译任何ARM汇编代码,该工具的调用方式如下:
arm-elf-as -marm7tdmi --gdwarf2 -o filename.o filename.s
其中:
Filename 需要编译的文件。
-marm7tdmi 告诉GNU汇编器你的CPU内型是ARM7TDMI(ARMv4T 版本)。
--gdwarf2 让汇编器附带输出DEBUG信息
GNU Assembler Reference的第一章,第二章以及8.4节列出了其他选项。对于大的工程来说,必须按模块划分成多个源文件。每个源文件(后缀为.s)的编译方法和上面所示的单个文件的方法一样。
当你已经把源文件编译成二进制目标文件(后缀名.o)后,可以使用GNU链接器生成最终的可执行文件(后缀.elf),调用方式如下:
arm-elf-ld -o filename.elf filename.o
一次又一次的输入命令行将十分枯燥(尽管Unix Shell允许你使用方向键的向上键来显示上一次的命令),为了解决上述问题,你可以修改GNU提供的Makefile模板来达到你自己的目的(该模板的路径为:examples/templates/Makefile.template-asm)。一旦修改完该文件(并且重新命名该文件:Makefile),接下来所要做的就是输入命令:
Make
汇编语言语法
GNU汇编器支持多种架构的CPU而不仅仅是ARM。正因为如此,它的汇编语法和其他的ARM汇编器有细微的区别。GNU汇编器对于其支持的45种CPU架构采用相同的汇编语法。汇编源文件由声明(每行一个)组成,声明格式如下,声明的每个部分都是可选的。
label: instruction ; comment
label可以确定其所在位置的程序计数器(pc)值,然后你就可以使用它。例子:在分支或者load和store指令中的目标。一个标号可以由任何有效的字符和冒号组成,所谓有效的字符包含以下字符:字母A-Z,a-z,数字0-9,符号"_",".","$"。但是要注意的是标号不能以数字开头(更多信息请看GNU Assembler Reference的3.4和5.3节)。
Comment以";"开头,不管是什么内容。除了在字符串中出现的分号,系统将忽律整行。C语言风格的注释(/*……*/)也同样被支持,同样的你也可以使用"@"来代替分号";"。
Instruction区域是你的程序的主要组成:你可以使用任何你想用的ARM汇编语言指令。 同样包括所谓的伪指令或者汇编命令(用来告诉汇编器自己干某些特殊的事)。这些汇编命令将在下面做详细介绍。
汇编命令
所有的汇编命令都是以"."开头。这些命令在GNU Assembler Reference的第七章做了更加详细的介绍。下面所列出的这些命令(按字母排列)是在程序中最常用的。
.align
插入0到3个字节的0x00,,这样下一个位置将是4字节的整数倍。特别的,ARM微控制器总是按字(4字节)读取数据。下面的例子中,输出对象文件中将被插入8字节的内容,假设第一行代码的位置是4字节的整数倍。
.byte 0x55 ; 插入1个字节 0x55
.align ; 顺次插入3个字节: 0x00 0x00 0x00
.word 0xAA55EE11 ; 插入内容 0x11 0xEE 0x55 0xAA (小端模式)
顺便说一下,前缀0x表示这个数是个16进制数,这个文档后面的表达式部分将对此做详细介绍。这个汇编命令还可以带选项,不过这儿不做介绍。如果你想使用它们,建议你用.balign命令代替。更多信息请看GNU Assembler Reference的7.3。
.ascii "string" …
在对象文件中按照指定的方法插入数字字符串,该字符串末尾没有NUL字符。该命令一次可以插入多个字符串,字符串之间用","分隔。下面的例子在对象文件中插入3个字节长的字符串。
.ascii "JNZ" ; 插入3个字节: 0x4A 0x4E 0x5A
.asciz "string" …
和.ascii相似,只是生成的字符串以NUL(0x00)结尾。下面的例子在对象文件中插入4个字节长的字符串。
.ascii "JNZ" ; 插入4个字节: 0x4A 0x4E 0x5A 0x00
.byte expression …
在对象文件中插入一个字节,内容为expression的值。可以一次插入多个表达式,以","分隔。下面的例子中共向对象文件中插入了5个字节内容。
.byte 64, 'A' ; 插入2字节 0x40 0x41
.byte 0x42 ; 插入字节 0x42
.byte 0b1000011, 0104 ; 插入2字节 0x43 0x44
注意以0x和0X开头的数字表示该数字是十六进制,以0b和0B开头的数字表示该数字是二进制,以0开头的数字表示该数字是八进制。这个文档后面的表达式部分将对此做详细介绍,同时请看.hword 和 .word 汇编命令部分。
.data
选择该命令以下的内容位于最终可执行文件的数据段。所有的可执行程序至少包含两个段,.我们称之为.text和.data段。(缺一段)
技术上来讲,意味着只有可执行的代码才能出现在.text段(尽管只读恒量也同样适合),可读写的数据才能出现在.data段,不过对于GNU汇编器来说,这并不是强制的。GNU Assembler Reference的第四章将深入讨论这个主题。
.end
标记一个源代码文件的结尾。所有的在这个命令之后的内容将被汇编器忽略。这个命令完全可选,但强烈建议使用。
.equ symbol, expression
设置symbol的值为expression。这个汇编指令和.set,"="完全一样。下面的例子admas的值都是42:
.equ adams, (5 * 8) + 2
.set adams, 0x2A
adams = 0b00101010
.extern symbol
声明symbol的定义在其他源文件中。这个命令是可选的,因为汇编器对于任何未定义的标号都默认为是外部定义的。不过仍然建议使用。
|
评论暂时关闭