GNU汇编语法.docx

上传人:b****8 文档编号:28070440 上传时间:2023-07-08 格式:DOCX 页数:10 大小:20.89KB
下载 相关 举报
GNU汇编语法.docx_第1页
第1页 / 共10页
GNU汇编语法.docx_第2页
第2页 / 共10页
GNU汇编语法.docx_第3页
第3页 / 共10页
GNU汇编语法.docx_第4页
第4页 / 共10页
GNU汇编语法.docx_第5页
第5页 / 共10页
点击查看更多>>
下载资源
资源描述

GNU汇编语法.docx

《GNU汇编语法.docx》由会员分享,可在线阅读,更多相关《GNU汇编语法.docx(10页珍藏版)》请在冰豆网上搜索。

GNU汇编语法.docx

GNU汇编语法

GNU汇编语法

Version:

1.0

2021-5-29

姜小科

youhan..

    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 ; ment

label可以确定其所在位置的程序计数器(pc)值,然后你就可以使用它。

例子:

在分支或者load和store指令中的目标。

一个标号可以由任何有效的字符和冒号组成,所谓有效的字符包含以下字符:

字母A-Z,a-z,数字0-9,符号"_",".","$"。

但是要注意的是标号不能以数字开头(更多信息请看GNU Assembler Reference的3.4和5.3节)。

ment以";"开头,不管是什么内容。

除了在字符串中出现的分号,系统将忽律整行。

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的定义在其他源文件中。

这个命令是可选的,因为汇编器对于任何未定义的标号都默认为是外部定义的。

不过仍然建议使用。

.global symbol

声明symbol是全局可见的。

标号_start是GNU器用来指定第一个要执行指令所必须的,同样的是全局可见的(并且只能出现在一个模块中)。

.hword expression …

.2byte expression …

在对象文件中插入半字(16位),内容为expression的值。

可以同时插入多个,以","分隔。

这个两个命令是一样的。

下面的例子在对象文件中插入8个字节内容。

    .hword 0xAA55, 12345       ; 插入4字节:

0x55 0xAA 0x39 0x30

    .2byte 0x55AA, -1          ; 插入4字节 0xAA 0x55 0xFF 0xFF

                                  ; 假设小端模式

注意ARM微控制器在16位地址边界上,一次总是读取16位数据,换句话说,它不能一次读取16位数据在一个奇数地址上。

请参考.align命令寻找解决方法。

同时参考.byte和.word命令。

.include "filename"

在当前源文件中插入filename的内容。

这和C语言的#include是同样的效果,所以通过这个命令也可以包含定义变量的头文件。

顺便提一下,注意被包含文件中是否有.end:

汇编器将忽略后面的所有的内容。

.ltorg

    插入存储恒量的文字池。

文字池是ARM汇编语言的伪指令 ldr = 和 adrl所使用。

这个汇编指令用的很少,因为GNU汇编器会准确的计算出什么时候,什么地方放置文字池。

尽管如此,有些场合该命令仍十分有用,比方说你想在一个特定地址放置你的代码。

.set symbol, expression

    这个命令和.equ一样,选择哪个是个人的偏好,不过建议使用一致的命令。

.skip expression

    在目标输出文件中跳过expression个字节。

被跳过的字节的值是不可预计的,尽管它们一般被初始化为0。

这个命令在声明有确定长度但没初始化值的变量特别有用。

下面这个例子声明了三个变量,前两个已经初始化,最后一个(buffer)没有初始化。

    head_ptr:

 .word 0 ; 初始化为0

    tail_ptr:

 .word 0 ; 初始化为0

    buffer:

 .skip 512 ; 512个字节未初始化

请参考 .ascii, .asciz, .byte, .hword and .word 等初始化值命令。

.text

    选择该命令以下的内容位于最终可执行文件的text(代码)段。

汇编程序指令必须放置在这个段。

请参考.data命令的相对详细说明。

.word expression …

.4byte expression …

    在对象文件中插入字(32位),内容为expression的值。

可以同时插入多个,以","分隔。

这个两个命令是一样的。

下面的例子在对象文件中插入8个字节内容。

    .word 0xDEADBEEF           ; 插入字节:

 0xEF 0xBE 0xAD 0xDE

    .4byte -42                  ; 插入字节 0xD6 0xFF 0xFF 0xFF

                                  ; 假设小端模式

    注意ARM微控制器在32位地址边界上,一次总是读取32位数据,换句话说,它不能一次读取32位数据在一个最低两位不为0的地址上。

请参考.align命令寻找解决方法。

同时参考.byte和.hword命令。

这些在其他处理器中不起眼的细节必须记住,在ARM术语中,字表示32位,而非16位。

Expressions(表达式)

    许多ARM汇编指令甚至汇编命令需要不同类型的整数来做操作数,象"mov r0,#1",需要数字"1"。

可以这么认为,一个表达式任何地方都可能会出现数字。

在最根本的层面上,一个表达式可以是一个简单的数字。

这个数字可以表现为十进制(不带前缀),十六进制(0x或0X前缀),八进制(以0开头)或者二进制(0b或0B前缀)。

它同样可以表现为字符常量,其形式为'a'或'a。

下面例子中6行代码都向ro赋一样的值:

74。

     mov r0,#74              ; 十进制数 74

     mov r0,#0x4A            ; 十六进制数 0x4A (0X4A 和0x4a 是一样的)

     mov r0,#0112            ; 八进制数 0112

     mov r0,#0b1001010      ; 二进制数 0b1001010 (0B1001010 是一样的)

     mov r0,#'J'             ; 字符常量 "J" (首选语法)

    mov r0,#'J              ; 字符常量 "J" (备选语法)

    当然,一个好的程序将用以下的方法来定义一个记号:

    .set letter_J, 'J' ; 这是一个实际设计例子

    mov r0, #letter_J

    字符常量可以像C语言中那样包含无固定顺序的反斜杠,更多细节请参考GNU Assembler Reference的3.6节

    除简单的整数外,表达式可以看起来像C语言中标准的数学和逻辑表达式一样,GNU Assembler Reference的第六章将详细描述这些方式。

下面是一些例子:

    .set ROM_size, 128 * 1024                ; 131072 字节 (128KB)

    .set start_ROM, 0xE0000000

    .set end_ROM, start_ROM + ROMsize       ; 0xE0020000

    .set bm1, 0b11001101                       ; 二进制掩码 (十六进制:

 0xCD)

    .set val1, -2 * 4 + (45 / (5 << 2))     ; -6 (in two's plement)

    .set val2, ROM_size >> 10                 ; 128 (131072 右移 10位)

    .set val3, bm1 | 0b11110000              ; bm1 OR 0b11110000 = 0b11111101

    就像上面的例子一样,表达式同样可以包含已定义的标号。

这样,表达式可以产生绝对的值和相对的的值,绝对值和它们在最终文件中的位置无关,是一个简单的数字常量。

另一方面,相对值和一些地址(比方说.data的地址)有关,它们的最终位置取决于器生成最终可执行文件的时候,和汇编器无关。

    相对值一般用于计算偏移,并且只能用"+"和"-"操作符。

以下是例子:

     .text

code_start:

     XXX ; 汇编指令...

code_end:

    .set instr_size, 4    ; 在ARM中指令都是4个字节长

    .set code_length, code_end - code_start

    .set first_instr, code_start

    .set instr_11th, code_start + 10 * instr_size

    .set instr_10th, instr_11th - instr_size

    code_length标号被设置成一个绝对的值(code_end 和code_start的差值)。

其他的标号,first_instr,instr_11th 和 instr_10th的值都取决于.text的值,它们真正的值只有在最终可执行文件生成时才能知道。

    一般来说,以下规那么适用于相对表达式:

    相对值 + 绝对值 ->?

 相对值

    绝对值 + 相对值 ->?

 相对值

    相对值 – 绝对值  ->?

 相对值

    相对值 – 相对值  ->?

 绝对值

所有其他包括相对值的表达式都是非法的(当然除了简单的标号自身的情况),请注意标号的相对计算只能基于在同一段的标号,比方说你不能得到一个位于.text段的标号和一个位于.data段标号之间的差值。

如果你需要,可以找到更多关于相对表达式的信息在GNU Assembler Reference的4.1节。

程序例子

正像开场时所说的,examples 文件夹 和它的子文件夹包含很多汇编语言例子程序。

这些例子涉及基于ARM微控制器的GNU汇编器各个方面,建议你去学习这些例子,最起码要快速的浏览一遍!

特别是examples/intro目录中的那些例子文件,请按下面的顺序学习:

    simple.s 一个简单的ARM汇编程序, 可以用它来起步

    subr.s 简单的之程序 (函数调用)

    values.s 给存放器装载常量, 使用 ldr =

    pseudo.s 更多的信息关于ARM伪指令

    jumptbl.s 分支调用函数

    wordcopy.s 拷贝一块存储在.data段中的多个字组成的区域

    blockcopy.s 用堆栈来拷贝一块集中区域的数据

    copy.s 拷贝一个以null结尾的字符串到内存 (汇编模块)

    strcopy-a.s 拷贝字符串使用多个源文件, 需要用到copy.s

    strcopy-c.c 拷贝字符串使用C和汇编混合编程, 需要用到copy.s

    你可以通过拷贝那个文件夹下所有的文件到一个临时文件夹来建立联合的可执行文件,使用make:

     mkdir –p ~/intro                       # 建立文件夹来放置文件

     cd /mnt/cdrom/examples/intro        # 假设 CD-ROM 被加载在 /mnt/cdrom

     cp * ~/intro                           # 拷贝文件    

     cd ~/intro                              # 进入文件夹

     chmod 644 *                             # 修改这些文件的权限为可读写

     make all                                 # 生成可执行文件

    你可以用arm-elf-gdb或arm-elf-insight提供的仿真器来仿真运行这些可执行文件,更多信息请参考GNU Debugger的An Introduction局部。

更多信息

你可以在GNU Assembler Reference中被叫做Using AS的局部找到更多关于GNU汇编器的信息,这个200多页的文档相当的全面虽然界面不算友好。

在 gnutools/doc 目录下可以找到这个文档。

对GNU汇编器来说最权威的参考就是真实的源代码。

你可以在gnutools/src/binutils-version.tar.gz文件中找到它们。

在解压完压缩文件并打上相应的补丁后,试着在gas子目录中浏览源代码文件。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 工作总结汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1