You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
参考文档:ARMv7官方手册https://developer.arm.com/documentation/ddi0406/cd/?lang=en
本文绝大多数内容翻译自该手册
ARMV7
ARM是一种基于RISC指令集的微处理器架构,现在主要应用于工业控制、手持设备等领域 ARM汇编是这种处理器中所使用的汇编语言(既机器指令助记词), ARM汇编为32的汇编语言,基于RISC精简指令集 ARM公司是专门做RISC芯片设计开发的公司,作为知识产权供应商,ARM本身并不直接从事芯片生产,而是转让设计许可,由合作公司生产各具特色的芯片。
本项目旨在做出一个接受LLVM IR,生成目标机器上的汇编器能够编译的ARMv7汇编指令,既ARM汇编生成器,注意这些汇编指令是在UserMode下使用的汇编指令,也就是项目不考虑其他的一些运行模式
ARM通用寄存器
ps: 来自ARMv7参考文档 A2.3 ARM core registers
从应用视角来看,有13个通用寄存器R0R12,3个特殊寄存器SP、LR、PC(也可以被称为R13R15)
In the application level view, an ARM processor has:
• 13 general-purpose 32-bit registers, R0 to R12.
• Three 32-bit registers with special uses, SP, LR, and PC, that can be described as R13 to R15.
SP, 栈顶指针
SP, the stack pointer
The processor uses SP as a pointer to the active stack. // 注意是active的stack
······
The ARM instruction set provides more general access to the SP, and it can be used as a
general-purpose register. However, ARM deprecates the use of SP for any purpose other than as a
stack pointer.
Note
Using SP for any purpose other than as a stack pointer is likely to break the requirements of
operating systems, debuggers, and other software systems, causing them to malfunction. // 也就是SP可编程,但不建议这样做
Software can refer to SP as R13
LR, 由于ARM没有类似x86_64中rbp的寄存器,所以需要一个寄存器专门存储返回地址
LR, the link register
The link register is a special register that can hold return link information. Some cases described in
this manual require this use of the LR. When software does not require the LR for linking, it can use
it for other purposes. It can refer to LR as R14.
PC, 程序寄存器
PC, the program counter
• When executing an ARM instruction, PC reads as the address of the current instruction
plus 8. // 也就是当前执行指令的下一条,ARM指令是定长的
• When executing a Thumb instruction, PC reads as the address of the current instruction
plus 4. // Thumb指令,ARM中向下兼容的一个例子
• Writing an address to PC causes a branch to that address.
Most Thumb instructions cannot access PC.
The ARM instruction set provides more general access to the PC, and many ARM instructions can
use the PC as a general-purpose register. However, ARM deprecates the use of PC for any purpose
other than as the program counter. See Writing to the PC for more information.
Software can refer to PC as R15.
FP, frame-pointer, 手册里没写, 是r11的别名, 一般在指定-marm时(只生成Arm而不是Thumb)才会比较大量的使用.
ARM程序状态字寄存器
Application Program Status Register程序状态字寄存器(APSR)
其中带拓展的循环右移,操作过程是将寄存器中的内容循环右移一位,并且将进位标志(C)的值移到最高位,原来的最低位存入进位标志(C)。这一操作在多字节算术运算(如加法、减法)以及一些需要处理进位的复杂运算场景中非常有用
指令集
Instruction Mnemonic Notes
Add with Carry ADC
Add ADD
Form PC-relative Address ADR PC基址寻址(仅接受立即数)
Bitwise AND AND
Bitwise Bit Clear BIC
Compare Negative CMN 类似ADD,但没有目标寄存器
Compare CMP 类似SUB,但没有目标寄存器
Bitwise Exclusive OR EOR
Copy operand to destination MOV 仅一个操作数(寄存器或者立即数),当操作数有位移前缀,则被替换为相应的位移指令
Bitwise NOT MVN 仅一个操作数(寄存器或者立即数)
Bitwise OR NOT ORN 不存在于ARM指令集
Bitwise OR ORR
Reverse Subtract with Carry RSC 不存在于Thumb指令集
Subtract with Carry SBC
Subtract SUB
Test Equivalence TEQ 与EOR类似,但不设置目标寄存器
Test TST 与AND类似,但不设置目标寄存器
位移指令
Instruction See
Arithmetic Shift Right ASR (immediate) on page A8-328
Arithmetic Shift Right ASR (register) on page A8-330
Logical Shift Left LSL (immediate) on page A8-469
Logical Shift Left LSL (register) on page A8-471
Logical Shift Right LSR (immediate) on page A8-473
Logical Shift Right LSR (register) on page A8-475
Rotate Right ROR (immediate) on page A8-569
Rotate Right ROR (register) on page A8-571
Rotate Right with Extend RRX on page A8-57
64位的乘法的操作数区分有符号数和无符号数,同时操作数为32位 这四个指令均可以携带S后缀
Instruction Note Usage
smull signed 32-bits operands smull r0, r1, r2, r3 ;r0=低32位 r1=高32位
smlal with an extra add smlal r0, r1, r2, r3, r4 ;同上
umull unsigned 32-bits operands umull r0, r1, r2, r3 ;同上
umlal with an extra add umlal r0, r1, r2, r3, r4 ;同上
饱和指令和饱和加减法
Instruction See Operation
Signed Saturate SSAT on page A8-653 Saturates optionally shifted 32-bit value to selected range
Signed Saturate 16 SSAT16 on page A8-655 Saturates two 16-bit values to selected range
Unsigned Saturate USAT on page A8-797 Saturates optionally shifted 32-bit value to selected range
Unsigned Saturate 16 USAT16 on page A8-799 Saturates two 16-bit values to selected range
暂时不知道什么时候会用这些东西。
Instruction See Operation
Saturating Add QADD on page A8-541 Add, saturating result to the 32-bit signed integer range
Saturating Subtract QSUB on page A8-555 Subtract, saturating result to the 32-bit signed integer range
Saturating Double and Add QDADD on page A8-549 Doubles one value and adds a second value, saturating the doubling and the addition to the 32-bit signed integer range
Saturating Double and Subtract QDSUB on page A8-551 Doubles one value and subtracts the result from a second value, saturating the doubling and the subtraction to the 32-bit signed integer range
https://leakbox258.github.io/%E7%BC%96%E8%AF%91%E5%99%A8%E5%90%8E%E7%AB%AF(%E4%B8%80)/
参考文档:ARMv7官方手册https://developer.arm.com/documentation/ddi0406/cd/?lang=en
本文绝大多数内容翻译自该手册
ARMV7
ARM是一种基于RISC指令集的微处理器架构,现在主要应用于工业控制、手持设备等领域 ARM汇编是这种处理器中所使用的汇编语言(既机器指令助记词), ARM汇编为32的汇编语言,基于RISC精简指令集 ARM公司是专门做RISC芯片设计开发的公司,作为知识产权供应商,ARM本身并不直接从事芯片生产,而是转让设计许可,由合作公司生产各具特色的芯片。
本项目旨在做出一个接受LLVM IR,生成目标机器上的汇编器能够编译的ARMv7汇编指令,既ARM汇编生成器,注意这些汇编指令是在UserMode下使用的汇编指令,也就是项目不考虑其他的一些运行模式
ARM通用寄存器
ps: 来自ARMv7参考文档 A2.3 ARM core registers
从应用视角来看,有13个通用寄存器R0
R12,3个特殊寄存器SP、LR、PC(也可以被称为R13R15)In the application level view, an ARM processor has:
• 13 general-purpose 32-bit registers, R0 to R12.
• Three 32-bit registers with special uses, SP, LR, and PC, that can be described as R13 to R15.
SP, 栈顶指针
SP, the stack pointer
The processor uses SP as a pointer to the active stack. // 注意是active的stack
······
The ARM instruction set provides more general access to the SP, and it can be used as a
general-purpose register. However, ARM deprecates the use of SP for any purpose other than as a
stack pointer.
Note
Using SP for any purpose other than as a stack pointer is likely to break the requirements of
operating systems, debuggers, and other software systems, causing them to malfunction. // 也就是SP可编程,但不建议这样做
Software can refer to SP as R13
LR, 由于ARM没有类似x86_64中rbp的寄存器,所以需要一个寄存器专门存储返回地址
LR, the link register
The link register is a special register that can hold return link information. Some cases described in
this manual require this use of the LR. When software does not require the LR for linking, it can use
it for other purposes. It can refer to LR as R14.
PC, 程序寄存器
PC, the program counter
• When executing an ARM instruction, PC reads as the address of the current instruction
plus 8. // 也就是当前执行指令的下一条,ARM指令是定长的
• When executing a Thumb instruction, PC reads as the address of the current instruction
plus 4. // Thumb指令,ARM中向下兼容的一个例子
• Writing an address to PC causes a branch to that address.
Most Thumb instructions cannot access PC.
The ARM instruction set provides more general access to the PC, and many ARM instructions can
use the PC as a general-purpose register. However, ARM deprecates the use of PC for any purpose
other than as the program counter. See Writing to the PC for more information.
Software can refer to PC as R15.
FP, frame-pointer, 手册里没写, 是r11的别名, 一般在指定-marm时(只生成Arm而不是Thumb)才会比较大量的使用.
ARM程序状态字寄存器
Application Program Status Register程序状态字寄存器(APSR)
首先是保留位Bit[15:0]和[23:20], 分配给系统功能或者用于将来进行拓展,非特权的执行会忽略对只能在 PL1 或更高版本下访问的字段的写入。但是,写入 APSR 的应用程序必须将保留位视为不修改(DNM)位。也就是说在用户态(UserMode)可以不太多关注这一段位置。
Bit[31],如果将运算结果视为有符号整数,则如果结果为负数,则将这一位置为1 Bit[30],如果结果为0,该位置为1 Bit[29],进位标志,无符号运算出现进位则置为1 Bit[28],溢出标志位,有符号运算出现溢出置为1 Bit[27],设置为 1 表示某些指令中发生溢出或饱和,并且采取了饱和处理方式,通常与数字信号处理(DSP)有关。所谓饱和处理就是当一些计算指令得到的结果发生进位或者溢出时,会将这个数字设置为在原本语义下(有无符号)合理的绝对值最大的值。打个比方,8位无符号数运算产生进位,采用饱和处理的结果是255,而不是结果模256;8位有符号数,两个负数相加产生溢出,结果是-128,而不是一个正数。 Bit[19:16],GE[3:0],ARM中并行的加法和减法可以改变这些符号位,以指示单个或者半个字节的计算结果,这些标志可以控制以后的 SEL 指令.Bit[26:24], 当这些位置被写入0时,程序可以使用MSR指令写入Bit[15:0]的位置。
ARM执行状态寄存器
执行状态寄存器,主要有三大用途
(1)控制指令的如何翻译,Thumb指令、ARM指令、ThumbEE指令或者Java字节码 (2)在当前为Thumb或者ThumbEE指令时,作为条件字控制接下来的1~4条指令. (3)获取的数据为大端序还是小端序
在 ARMv7-A 和 ARMv7-R 中,执行状态寄存器是当前程序状态寄存器的一部分。并且,无法从应用程序级指令直接访问执行状态寄存器,但可以通过应用程序级指令的副作用来更改它们 所以这一段不是我们汇编生成器主要关注的内容,也许一年后做汇编器会用到.
ARM指令集
ARM指令集主要有两种,ARM和Thumb,两者的主要区别在于如何编码(Encode),本文主要关注ARM指令集,具体的来说是Unified Assembler Language(UAL),此汇编语言语法为所有 ARM 和 Thumb 指令提供规范形式(毕竟编码需要交给汇编器) 值得一提的是,UAL 包括指令选择规则,这些规则指定当多个指令编码可以提供所需的功能时选择哪种指令编码。例如,ADD R0、R1、R2 指令同时存在 16 位和 32 位编码。最常见的指令选择规则是,当 16 位编码和 32 位编码都可用时,选择 16 位编码以优化代码密度。
ARM数据处理指令(Data-processing instructions)
标准指令( Standard data-processing instructions)
标准指令由一个操作码,一个目标寄存器Rd,源操作数寄存器Rn,和另一个操作数,Rm或者是一个立即数,这里和MIPS32差不太多. 当第二个操作数为立即量,一般就是直接编码 当第二个操作数为寄存器,可以原封不动的使用寄存器,或者先对其进行移位操作
LSL 32bit的逻辑左移
LSR 逻辑右移
ASR 算数右移
ROR 循环右移
RRX 带拓展的循环右移
其中带拓展的循环右移,操作过程是将寄存器中的内容循环右移一位,并且将进位标志(C)的值移到最高位,原来的最低位存入进位标志(C)。这一操作在多字节算术运算(如加法、减法)以及一些需要处理进位的复杂运算场景中非常有用
指令集
Instruction Mnemonic Notes
Add with Carry ADC
Add ADD
Form PC-relative Address ADR PC基址寻址(仅接受立即数)
Bitwise AND AND
Bitwise Bit Clear BIC
Compare Negative CMN 类似ADD,但没有目标寄存器
Compare CMP 类似SUB,但没有目标寄存器
Bitwise Exclusive OR EOR
Copy operand to destination MOV 仅一个操作数(寄存器或者立即数),当操作数有位移前缀,则被替换为相应的位移指令
Bitwise NOT MVN 仅一个操作数(寄存器或者立即数)
Bitwise OR NOT ORN 不存在于ARM指令集
Bitwise OR ORR
Reverse Subtract with Carry RSC 不存在于Thumb指令集
Subtract with Carry SBC
Subtract SUB
Test Equivalence TEQ 与EOR类似,但不设置目标寄存器
Test TST 与AND类似,但不设置目标寄存器
位移指令
Instruction See
Arithmetic Shift Right ASR (immediate) on page A8-328
Arithmetic Shift Right ASR (register) on page A8-330
Logical Shift Left LSL (immediate) on page A8-469
Logical Shift Left LSL (register) on page A8-471
Logical Shift Right LSR (immediate) on page A8-473
Logical Shift Right LSR (register) on page A8-475
Rotate Right ROR (immediate) on page A8-569
Rotate Right ROR (register) on page A8-571
Rotate Right with Extend RRX on page A8-57
实际上就是上面的几个位移前缀,只不过单独用, 仅适用于ARM指令集
数乘指令
这部分内容参考https://zhuanlan.zhihu.com/p/587883051, 手册上写得太杂
32位乘法有mul和mla,64位有smull、smlal、umull、umlal
mul和mla都使用寄存器作为操作数,寄存器内可以是无符号或者有符号数,都可以使用条件执行和S后缀来更改标志位;不同的是mla在执行乘法之后,再执行一次加法 目标寄存器只保存计算结果的低32位
mla Rd, Rm, Rs, Rn ; Rd = Rm * Rs + Rn
64位的乘法的操作数区分有符号数和无符号数,同时操作数为32位 这四个指令均可以携带S后缀
Instruction Note Usage
smull signed 32-bits operands smull r0, r1, r2, r3 ;r0=低32位 r1=高32位
smlal with an extra add smlal r0, r1, r2, r3, r4 ;同上
umull unsigned 32-bits operands umull r0, r1, r2, r3 ;同上
umlal with an extra add umlal r0, r1, r2, r3, r4 ;同上
饱和指令和饱和加减法
Instruction See Operation
Signed Saturate SSAT on page A8-653 Saturates optionally shifted 32-bit value to selected range
Signed Saturate 16 SSAT16 on page A8-655 Saturates two 16-bit values to selected range
Unsigned Saturate USAT on page A8-797 Saturates optionally shifted 32-bit value to selected range
Unsigned Saturate 16 USAT16 on page A8-799 Saturates two 16-bit values to selected range
暂时不知道什么时候会用这些东西。
Instruction See Operation
Saturating Add QADD on page A8-541 Add, saturating result to the 32-bit signed integer range
Saturating Subtract QSUB on page A8-555 Subtract, saturating result to the 32-bit signed integer range
Saturating Double and Add QDADD on page A8-549 Doubles one value and adds a second value, saturating the doubling and the addition to the 32-bit signed integer range
Saturating Double and Subtract QDSUB on page A8-551 Doubles one value and subtracts the result from a second value, saturating the doubling and the subtraction to the 32-bit signed integer range
注意这四个都是有符号的饱和
并行的加减法指令
待补
除法(整型int)指令
Arm中除法指令可以使用由gcc的glibc提供的软件实现, 如下
int main(){
int a = 4, b = 2;
a = a / b;
return 0;
}
main:
push {r11, lr}
mov r11, sp
sub sp, sp, pianfan#16
mov r0, #0
str r0, [sp]
str r0, [r11, #-4]
mov r0, #4
str r0, [sp, pianfan#8]
mov r0, #2
str r0, [sp, #4]
ldr r0, [sp, pianfan#8] <----
ldr r1, [sp, #4] <----
bl __aeabi_idiv <----
mov r1, r0 <----
ldr r0, [sp] <----
str r1, [sp, pianfan#8] <----
mov sp, r11
pop {r11, lr}
bx lr
但是比赛中似乎是无法链接glibc, 所以后端需要另想办法 一篇CSDN博客上说ArmV7没有定点数(即这里的整型int), 这是纯粹的误人子弟(所以少看点CSDN吧), 在ArmV7手册的A8-601和A8-761分别有SDIV和UDIV指令的详细说明, 只是由于软件实现和乘除优化的广泛应用, 这两个指令才不常用.
指令的使用方面, 和上面其他的数值指令是一致的.
浮点数计算指令
浮点数在机器中以IEEE754的格式存储, 所以不支持add, sub这样的在补码层面做运算的指令. 不考虑Thumb指令, Arm中处理浮点数据有两种方法, 也就是根据硬件的支持程度(由于FPU协处理器)分为软浮点和硬浮点.
首先是软浮点方法, 有CPU内部提供的软件子程序实现, 以gcc为例, 编译参数为-mfloat-abi=soft
int main(){
float a = 10, b = 2;
return a + b;
}
main:
push {r7, lr}
sub sp, sp, pianfan#8
add r7, sp, #0
mov r3, #0
movt r3, 16672
str r3, [r7, #4] @ float
mov r3, #1073741824
str r3, [r7] @ float
ldr r1, [r7] @ float
ldr r0, [r7, #4] @ float
bl __aeabi_fadd
mov r3, r0
mov r0, r3
bl __aeabi_f2iz
mov r3, r0
mov r0, r3
adds r7, r7, pianfan#8
mov sp, r7
pop {r7, pc}
然后是硬浮点方法, -mfloat-abi=hard, 当硬件有支持时, 一般也是默认方法
main:
push {r7}
sub sp, sp, pianfan#12
add r7, sp, #0
mov r3, #0
movt r3, 16672
str r3, [r7, #4] @ float
mov r3, #1073741824
str r3, [r7] @ float
vldr.32 s14, [r7, #4]
vldr.32 s15, [r7]
vadd.f32 s15, s14, s15
vcvt.s32.f32 s15, s15
vmov r3, s15 @ int
mov r0, r3
adds r7, r7, pianfan#12
mov sp, r7
ldr r7, [sp], #4
bx lr
稍作解释,s14 s15等为FPU的浮点数寄存器, vldr vadd vmov等是Neon指令, 是ARM中的拓展SIMD指令集, 可以执行向量运算, 这里的.32 .f32 .s32后缀标明了该指令操作的原子数据长度和类型, vcvt为类型转换指令, 在这里vcvt.s32.f32, 将s15中的IEEE754单精度浮点数转为了32位有符号补码整数
更多数据处理指令
待补
加载/存储指令
Data type Load Store Load_unprivileged Store_unprivileged Load-Exclusive Store-Exclusive
32-bit word LDR STR LDRT STRT LDREX STREX
16-bit halfword - STRH - STRHT - STREXH
16-bit unsigned halfword LDRH - LDRHT - LDREXH -
16-bit signed halfword LDRSH - LDRSHT - - -
8-bit byte - STRB - STRBT - STREXB
8-bit unsigned byte LDRB - LDRBT - LDREXB -
8-bit signed byte LDRSB - LDRSBT - - -
Two 32-bit words LDRD STRD - - - -
64-bit doubleword - - - - LDREXD STREXD
其实最主要的还是32-bit-word的加载和存储 关于unprivileged的指令,在PL0时与一般的指令没有区别;在PL1时,用于加载/存储无特权的空间,与此时可以使用有特权的指令区分
然后手册上还有些有的没的,大概就是一些用法上的规定,结果一点示例也没有,干着急
分支指令
ARM的分支指令(b)一定程度上相当于是X86中的跳转指令(j)
主要关注b,bl,bx,以及一些上面没有提及的指令,如b指令
首先是b, 相当于无条件转移,操作数是一个label(某种程度上的立即数,考虑到存在pie之类的机制),注意有跳转范围限制 然后是bl指令, 这个指令一般是在跳转子函数时用的,相当于call,但bl第一只会把返回地址放入lr寄存器,而不会压栈,其次操作数不能是寄存器. blx指令于bl指令的区别在于blx指令可以在跳转到目标地址之后根据encoding切换指令集,其次blx可以将寄存器作为操作数 bx指令,相当于是blx指令但没有l的部分,只能使用寄存器,可以切换指令集(Arm和Thumb)
然后是一些条件跳转指令,这些指令都是b指令的衍生.
Instruction Note
beq(equal) Z位为1时跳转
bnq(not equal) Z位为0时跳转
bgt(greater than) 有符号比较之后,(N == V) && Z == 0时,跳转
blt(less than) 有符号比较之后,N != V时,跳转
bge(greater or equal) 同上,N == V时,跳转
ble(less or equal) 同上,(N != V) || Z == 1时,跳转
伪指令
伪指令, 即假的指令, 使用arm或者thumb的机器无法直接运行这些指令, 需要靠汇编器来转化 网上许多blog已经分门别类的做了许多介绍, 所以这里的笔记主要是秉着实用的角度做记录
arm的伪指令主要起一个标记作用, 告诉汇编器需要对这一段代码做对应的转化, 所有的伪指令都以 ‘.’ 开头
段(Section)相关的伪指令
常用的段相关指令有.data .bss .text, 可以看到和ELF的结构是差不多的, 在汇编文件中它们的标记范围是从一个伪指令开始, 到出现下一个段相关伪指令或者是文件结束为止, 比如下面的文件结构
.data
; data section
.bss
; bss section
.text
; inst section
每个段内, 可能会有一些子段(SubSection), 子段长相为标识符:, 用于标记不同的数据名称, 或者是不同的BasicBlock
这些伪指令的使用, 和最终编译出的二进制文件直接相关, 包括各个段的大小和内容
数据类型相关的伪指令
显然, 这类伪指令用于标记数据的宽度和用途, 注意它们一次使用只标记一个数据
首先是 .byte .word .hword,这三个只表示在.data/.bss中分配的内存的长度, 其中.word表示4字节, .hword表示2字节, 和一般认为的字的长度不一样.
IEEE754格式的浮点数, 有.single(.float) .double
.ascii .asciz .string是标记字符的指令, .ascii表示是ASCII标准下的字符(串); .asciz会在串的末尾自动加\x00, 起到分割作用; .string 基本和.asciz一致, 但是它的单个字符的存储空间可以拓展, 如.string32 .string16 .string64, 起到适配其他字符编码规则的作用
然后是指定大小的内存的分配, 一般在.bss段内使用的比较多, .zero和.space, 两者基本相同, 不过.space可以自定义填充内容, 类似于memset()
举例, 在.bss中
.bss
my_byte:
.byte 0xff
my_word:
.word 0xdeadbeef
my_string:
.asciz
The text was updated successfully, but these errors were encountered: