多年来,我一直在为 arm/thumb 编程很多汇编程序,并且只需要很少的许多指令。
正如另一位响应者指出的那样,.thumb_func 非常重要。
例如
.globl _start
_开始:
b 重置
重启:
。手臂
.globl 一
一:
添加 r0,r0,#1
bx lr
。拇指
.globl 二
二:
添加 r0,r0,#2
bx lr
.thumb_func
.globl 三
三:
添加 r0,r0,#3
bx lr
.字二
.word 三
.arm 或曾经是 .code32 或 .code 32 之类的东西告诉它这是 arm 代码而不是拇指代码,对于您的 cortex-m3,您不需要使用它。
.thumb 同样,以前是 .code 16 或者可能仍然有效,同样的处理使以下代码拇指不支持。
如果您使用的标签不是您需要从其他文件或间接分支到的全局标签,则不需要 .thumb_func。但是为了正确计算这些全局标签之一的分支地址(lsbit 是拇指的 1 和手臂的 0),您希望将其标记为拇指或手臂标签,thumb_func 会这样做,否则您必须在分支添加更多代码之前设置该位,并且标签不可从 C 调用。
00000000 <_开始>:
0: eaffffff b 4 <一>
00000004 <一>:
4: e2800001 添加 r0, r0, #1
8:e12fff1e bx lr
0000000c <二>:
c: 3002 添加 r0, #2
e: 4770 bx lr
00000010 <三>:
10: 3003 添加 r0, #3
12:4770 bx lr
14: 0000000c andeq r0, r0, ip
18: 00000011 andeq r0, r0, r1, lsl r0
到 .thumb 为止,汇编程序是根据需要的 arm 代码。
两个和三个标签/功能都是所需的拇指代码,但两个标签具有偶数地址,三个标签具有正确的奇数地址。
最新的 codesourcery 工具用于组装、链接和转储上述示例。
现在对于一切都是 thumb(/thumb2) 的 cortex-m3,thumb_func 可能不那么重要,它可能只适用于命令行开关(很容易做一个实验来找出)。但是,如果您从仅使用拇指的处理器转移到普通的手臂/拇指核心,这是一个好习惯。
汇编程序通常喜欢添加所有这些指令和其他使事物看起来/感觉更像高级语言的方法。我只是说你不必使用它们,我为 arm 切换了汇编器,并为许多不同的处理器使用了许多不同的汇编器,并且更喜欢少即是多的方法,这意味着专注于组装本身并尽可能少地使用特定于工具的项目. 我通常是例外而不是规则,因此您可以通过查看编译器输出生成的指令(并使用文档验证)来找出更常用的指令。
无符号整数一(无符号整数 x)
{
返回(x+1);
}
.arch armv5te
.fpu 软vfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 2
.eabi_attribute 18, 4
.file“鲍勃.c”
。文本
.对齐 2
.global 一
.type 一,%function
一:
.fnstart
.LFB0:
@args = 0,假装 = 0,帧 = 0
@frame_needed = 0,使用_anonymous_args = 0
@链接寄存器保存消除。
添加 r0, r0, #1
bx lr
.fnend
.size 一个,.-one
.ident“GCC:(Sourcery G++ Lite 2010.09-50)4.5.1”
.section .note.GNU-stack,"",%progbits
在将 arm 和 thumb 汇编器或数据与汇编器混合时,我确实使用了 .align,您会希望此类平台的汇编器知道一些显而易见的东西,例如 thumb 指令在半字边界上,而 arm 指令在字边界上对齐。这些工具并不总是那么聪明。洒 .aligns about 不会受到伤害。
.text 是默认值,所以有点多余,但不会受到伤害。.text 和 .data 是标准属性(不是特定于 arm),如果您在目标上编译 rom 和 ram 的组合,您可能会关心(取决于您对链接器脚本的操作),否则 .text 将适用于所有内容.
.size 显然是该指令开始的函数的大小。汇编器不能自己解决这个问题,所以如果这个函数的大小对你的代码、链接器脚本、调试器、加载器很重要,那么这需要是正确的,否则你不必费心。无论如何,函数是一个高级概念,汇编程序实际上并没有函数,更不用说声明它们的大小了。C 编译器当然不在乎,它只是在寻找要分支到的标签,在 arm 系列的情况下,它是要分支到的拇指代码还是 arm 代码。
如果您在很长一段代码上对立即数 (ldr rx,=0x12345678) 很懒惰,您可能会发现 .pool 指令(有一个较新的等效指令)很有用。同样,这些工具并不总是足够聪明,无法将这些数据放在无条件分支之后,您有时会告诉他们。我说懒惰一半是认真的,一直做标签是痛苦的: .word 事情,我相信 arm 和 gcc 工具都允许使用该快捷方式,所以我和其他人一样使用它。
还要注意 llvm 输出一个或两个额外的 .eabi_attribute ,它由 code sourcery 的 version/mods 支持到 binutils 但不被 gnu 发布的 binutils 支持(可能还没有)。两种可行的解决方案,修改 llvm 的 asm 打印函数以不编写 eabi_attributes 或至少用注释 (@) 编写它们,或者从代码源中获取 binutils 源/模块并以这种方式构建 binutils。代码源倾向于引导 gnu(例如,thumb2 支持)或者可能向后移植新功能,所以我认为这些 llvm 属性很快就会出现在主线 binutils 中。通过从 llvm 编译代码中删除 eabi_attributes,我没有受到任何不良影响。
这是上面相同函数的 llvm 输出,显然这是我修改以注释掉 eabi_attributes 的 llc。
.syntax 统一
@ .eabi_attribute 20, 1
@ .eabi_attribute 21, 1
@ .eabi_attribute 23, 3
@ .eabi_attribute 24, 1
@ .eabi_attribute 25, 1
@ .eabi_attribute 44, 1
.file “bob.bc”
。文本
.globl 一
.对齐 2
.type一,%函数
一一
@BB#0: @%entry
添加 r0, r0, #1
bx lr
.ltmp0:
.size 一个,.Ltmp0-one
如果您想真正了解 elf 特定指令(如果有的话)在做什么,elf 文件格式有很好的文档记录并且很容易解析。其中许多指令对链接器的帮助比什么都大。例如,.thumb_func、.text、.data。