我已经编写了很多ARM/Thumb汇编语言程序,并且只需要使用其中少量的许多指令。正如另一位回答者所指出的,
.thumb_func
非常重要。
例如:
.globl _start
_start:
b reset
reset:
.arm
.globl one
one:
add r0,r0,#1
bx lr
.thumb
.globl two
two:
add r0,r0,#2
bx lr
.thumb_func
.globl three
three:
add r0,r0,#3
bx lr
.word two
.word three
.arm
或曾经是
.code32
或
.code 32
告诉编译器这是ARM代码而不是Thumb代码,在您的Cortex-M3中不需要使用它。
类似地,
.thumb
曾经是
.code 16
或者可能仍然有效,它使得接下来的代码是Thumb而不是ARM。
如果您正在使用的标签不是全局标签,并且您不需要从其他文件或间接地转移到该标签,则不需要使用
.thumb_func
。但是为了正确计算到这些全局标签之一的分支的地址(lsbit对于Thumb为1,对于ARM为0),您需要将其标记为Thumb或Arm标签,
.thumb_func
可以实现这一点,否则您必须在分支之前设置该位并添加更多代码,而且该标签无法从C中调用。
00000000 <_start>:
0: eaffffff b 4
00000004 :
4: e2800001 add r0, r0, #1
8: e12fff1e bx lr
0000000c :
c: 3002 adds r0, #2
e: 4770 bx lr
00000010 :
10: 3003 adds r0, #3
12: 4770 bx lr
14: 0000000c andeq r0, r0, ip
18: 00000011 andeq r0, r0, r1, lsl r0
在
.thumb
之前,汇编器是ARM代码,正如所需的那样。
两个函数的标签(two和three)都是Thumb代码,但two标签具有偶数地址,而three则具有正确的奇数地址。
上面的示例使用了最新的CodeSourcery工具进行汇编、链接和转储。现在在 cortex-m3 中,所有指令都是 Thumb(/Thumb2)
.thumb_func
,可能不那么重要,可以使用命令行开关(很容易进行实验以找出结果)。但是养成这个习惯还是很好的,以防从 Thumb-only 处理器转移到普通的 ARM/Thumb 核心。
汇编器通常喜欢添加所有这些指令和其他使事物看起来/感觉更像高级语言的方式。我只是说您不必使用它们,我为 ARM 切换了汇编器,并且对许多不同的处理器使用许多不同的汇编器,并倾向于更少即更好的方法,即专注于汇编本身并尽可能少地使用与工具相关的项目。我通常是例外而不是规则,因此您可以通过查看编译器输出生成的指令(并通过文档进行验证)来确定更常用的指令。
unsigned int one ( unsigned int x )
{
return(x+1);
}
.arch armv5te
.fpu softvfp
.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 "bob.c"
.text
.align 2
.global one
.type one, %function
one:
.fnstart
.LFB0:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
add r0, r0, #1
bx lr
.fnend
.size one, .-one
.ident "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1"
.section .note.GNU-stack,"",%progbits
当在 ARM 和 Thumb 汇编中混合代码或数据时,我会使用
.align
。您应该期望此类平台的汇编器知道 Thumb 指令位于半字边界上,ARM 指令位于字边界上。但是工具并不总是那么聪明。随处添加
.align
不会有害。
.text
是默认值,因此有点冗余,但不会有害。如果将目标编译为 ROM 和 RAM 的组合,则
.text
和
.data
是标准属性(不特定于 ARM),则您可能要考虑(取决于您如何使用链接器脚本),否则
.text
将适用于所有内容。
.size
显然是这个函数从开始到该指令的大小。汇编器无法自行确定,因此如果该函数的大小对您的代码、链接脚本、调试器、加载程序等很重要,则需要正确设置它,否则您就不必费心了。无论如何,函数都是一个高级概念,汇编器实际上没有函数,更不需要声明它们的大小。而且C编译器肯定不关心,它只在寻找一个标签以便能够跳转,而对于ARM体系结构来说,它是跳转到Thumb指令集还是ARM指令集。
如果你在长代码段上懒得使用你的立即数(ldr rx,=0x12345678
),那么你可能会发现.pool指令
(有一个更新的等效指令)很有用。在这种情况下,工具并不总是聪明地将这些数据放在无条件分支之后,有时您需要告诉它们。我半开玩笑地说“懒”,因为总是要做label:.word
的事情,而且我相信ARM和GCC工具都允许这种快捷方式,所以我像其他人一样经常使用它。
另外请注意,LLVM输出了一个额外的.eabi_attribute
或两个,在Code Sourcery版本/修改的binutils中得到了支持,但在GNU发布的binutils中不受支持(也许还没有)。两种解决方案有效,一是修改LLVM的asm打印函数,以便不写eabi_attributes
,或者至少用注释(@
)写它们;二是从Code Sourcery获取binutils源代码/修改,并以这种方式构建binutils。Code Sourcery往往领先于GNU(例如支持Thumb2),或者会将新功能回溯,因此我认为这些LLVM属性很快就会出现在主线binutils中。从LLVM编译的代码中删除eabi_attribute
对我没有产生任何不良影响。
以下是相同函数的LLVM输出,显然这是我修改过的llc,以注释掉eabi_attribute
。
.syntax unified
@ .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"
.text
.globl one
.align 2
.type one,%function
one: @ @one
@ BB#0: @ %entry
add r0, r0, #1
bx lr
.Ltmp0:
.size one, .Ltmp0-one
elf文件格式有很好的文档记录,如果你想真正了解elf特定指令(如果有的话)是在做什么,那么很容易解析。其中许多指令都是为了帮助链接器而不是其他任何东西。例如,
.thumb_func
,
.text
和
.data
。