内存管理-17-Arm64汇编

一、指令


1. Arm64汇编 lsr 指令

LSR是ARM架构的位移动指令,用于逻辑右移操作。它将第一个操作数的位向右移动指定位数,并根据需要将符号位(在有符号数操作中)扩展到空出来的位。

语法:

LSR{条件}{S} 移位量,寄存器

条件是可选的,指定为如 EQ、NE 等,用来指明只有在特定条件下才能执行指令。
S 是可选的,指定为 S 表示指令应该影响 CPSR 中的条件标志位,不指定则不影响条件标志位。
移位量是一个立即数,用来指定位移动的位数,范围通常是0到31。
寄存器是一个通用寄存器,包含要移位的值。

实例代码:

LSR R0, R0, #5 ; 将寄存器R0中的值逻辑右移5位

这条指令将寄存器R0中的值移动5位右边的位进入CPSR中,左边空出的位用0填充,符号位扩展也遵循这个规则。


2. Arm64汇编 add 指令

ADD 用于执行加法操作。它可以用于两个通用寄存器、一个通用寄存器和一个寄存器的内存地址、或者一个寄存器和一个立即数之间的加法。

以下是一些使用 ADD 指令的例子:

两个通用寄存器之间的加法:

ADD w0, w1, w2 ; 将 w1 和 w2 的内容相加,结果存储在 w0 中

通用寄存器与内存地址之间的加法:

ADD w0, w1, [x2] ; 将 w1 和内存地址 x2 指向的值相加,结果存储在 w0 中

通用寄存器与立即数之间的加法:

ADD w0, w1, #10 ; 将 w1 和立即数 10 相加,结果存储在 w0 中

请注意,ADD 指令可以有条件执行,例如,ADD 指令可以跟有条件后缀,如 EQ、NE、HS 等,这样只有在特定条件满足时才会执行加法操作。

 

3. Arm64汇编 orr 指令

orr 是 ARM 汇编语言中的一个逻辑指令,用于执行两个值的按位或操作。orr 指令可以对两个寄存器或寄存器和立即数进行操作。

语法格式如下:

orr {<cond>} <rd>, <rn>, <operand2>

<cond> 是可选的条件代码。
<rd> 是目标寄存器,用于保存结果。
<rn> 是第一个源寄存器,其内容将被操作。
<operand2> 是第二个源操作数,可以是一个寄存器或立即数值。

实例代码:

orr r0, r1, #0xF ; 将寄存器 r1 的值与立即数 0xF 进行按位或操作,结果存储在 r0 中
orr r2, r3, r4 ; 将寄存器 r3 的值与寄存器 r4 的值进行按位或操作,结果存储在 r2 中

在这个例子中,r0 将会是 r1 或上 0xF 的结果,r2 将会是 r3 或 r4 的结果。


4. arm64汇编 str 指令

str 是 ARM 汇编语言中的一个指令,用于将数据从寄存器传送到内存地址。####在 ARM 架构中,有多种不同的 str 指令,用于处理不同的数据类型和操作模式。

以下是一些使用 str 指令的示例:

(1) 将一个32位的寄存器值存储到内存中:

str r1, [r2]

这条指令会将寄存器 r1 的值存储到 r2 寄存器值指定的内存地址中。

(2) 将一个64位的寄存器值存储到内存中:

str r1, [r2]
str r1, [r2, #8]!

第一条指令会将 r1 的低64位存储到内存地址中。第二条指令会将 r1 的高64位存储到内存地址中,并且更新 r2 的值(使用后续的内存地址)。

(3) 将一个32位的寄存器值存储到带有偏移的内存地址中:

str r1, [r2, #16]

这条指令会将 r1 的值存储到 r2 的值加上16后得到的内存地址中。

(4) 将一个32位的寄存器值存储到带有索引的内存地址中:

str r1, [r2, lr]

这条指令会将 r1 的值存储到 r2 的值加上 lr 寄存器值得到的内存地址中。

(5) 将一个32位的常数存储到内存中:

str w3, [sp, #-4]!

这条指令会将常数w3存储到栈上,并更新 sp 寄存器的值(向下增长)。

(6) 将一个16位的寄存器值存储到内存中:

strh r1, [r2]

这条指令会将 r1 的低16位存储到内存地址中。

(7) 将一个8位的寄存器值存储到内存中:

strb r1, [r2]

这条指令会将 r1 的低8位存储到内存地址中。

(8) 使用 str 指令复制数据:

str r1, [r2]

这条指令会将 r1 寄存器中的值复制到 r2 寄存器指定的内存地址中。

注意:在使用 str 指令时,确保目标地址是可写的,否则会产生异常。

补充:这里给出不同指令下进行数据操作的位数:
ldrb/strb 8位操作
ldrh/strh 16位操作
ldr/str 32位操作
ldrd/strd 64位操作


5. Arm64汇编 .macro 指令

.macro 是 ARM 汇编语言中用于定义宏的指令。宏是一段可以重复使用的汇编代码,类似于 C 语言中的宏。使用 .macro 指令定义宏,使用 .endm 指令结束宏定义。

下面是一个简单的 .macro 使用例子:

.macro BLK_MOV_ALIGNED_I4 inptr, outptr, len, incr
mov x0, \inptr
mov x1, \outptr
mov x2, \len
mov x3, \incr
blk_mov_aligned_i4 x0, x1, x2, x3
.endm

在这个例子中,BLK_MOV_ALIGNED_I4 是宏的名称。宏接受四个参数:inptr, outptr, len, 和 incr。这些参数在宏的代码中通过 \param 的方式使用,其中 \inptr 代表输入指针参数,\outptr 代表输出指针参数,依此类推。

当宏被调用时,例如通过 BLK_MOV_ALIGNED_I4 x0, x1, x2, x3,它将把 x0, x1, x2, x3 分别赋值给 \inptr, \outptr, \len, \incr,然后执行 blk_mov_aligned_i4 x0, x1, x2, x3 指令。

注意:这只是一个假设的 blk_mov_aligned_i4 实现的宏例子,实际的 blk_mov_aligned_i4 是内核提供的一个函数,宏用于封装函数调用的参数。


6. Arm64汇编 mov 指令

在ARM架构中,mov 指令用于数据传送。在ARMv8 (arm64) 汇编中,mov 指令可以用于不同的数据类型,包括通用寄存器,寄存器的特定位,或者是寄存器和内存之间的数据传送。

以下是一些使用 mov 指令的例子:

(1) 将一个常数加载到寄存器中:

mov x0, #0x12345678 // 将常数0x12345678加载到x0寄存器中

(2) 将一个寄存器的值复制到另一个寄存器:

mov x1, x0 // 将x0寄存器中的值复制到x1寄存器中

(3) 将内存地址中的值加载到寄存器中:

mov x2, [x1] // 将x1寄存器指向的内存地址中的值加载到x2寄存器中

(4) 将一个特定的位从一个寄存器复制到另一个寄存器:

movk x0, #0x12, lsl #16 // 将0x12左移16位后,加载到x0寄存器的高16位中

(5) 将一个寄存器的值复制到另一个特定的寄存器(例如,将程序计数器的值复制到x0寄存器):

mov x0, pc // 将程序计数器的值复制到x0寄存器中

(6) 将一个寄存器的值复制到另一个特定的寄存器(例如,将链接寄存器x30的值复制到x0寄存器):

mov x0, x30 // 将链接寄存器的值复制到x0寄存器中

注意:在使用 mov 指令时,确保目标寄存器和源操作数的大小是兼容的,例如,不能直接将一个32位的值移动到一个64位的寄存器中,除非使用适当的扩展指令(如 movw 或 movn)。


7. Arm64汇编 b.ls 指令

b.ls 是一条条件分支指令,在 ARM 64 位汇编中,用于“less than and equal”的条件分支,即当比较的两个值中一个小于或等于另一个时,程序会跳转到指定的位置执行。

这条指令的全称是 "Branch Less Than or Equal",其语法格式如下:

b.ls <target_address>

其中 <target_address> 是你想要跳转到的地址。这条指令需要和状态寄存器中的条件标志一起工作,比如之前的一个比较指令 cmp 或者 ccmp 等可以设置条件标志的指令。

下面是一个使用 b.ls 的简单例子:

cmp x0, x1 // 比较寄存器x0和x1
b.ls label // 如果x0小于或等于x1,则跳转到label处执行

在这个例子中,cmp 指令用于比较寄存器 x0 和 x1,然后 b.ls 指令会检查比较的结果,如果 x0 小于或等于 x1,则程序会跳转到标签 label 指定的位置执行。

注意:b.ls 是 ARM 汇编的一个示例,具体的汇编语言和指令集可能会根据不同的处理器架构有所不同。


8. Arm64汇编 adrp 指令

ADRP 是 ARM 64 位汇编语言中的一个指令,用于生成一个基于程序计数器 PC 的相对偏移地址。ADRP 指令通常用于加载 4KB 对齐的内存地址,###### 通过页(4KB)对齐的方式,可以有效地利用硬件的缓存和内存系统。

ADRP 指令的格式如下:ADRP register, label | offset

其中,register 是目标寄存器,label 是代码中的标签或者其他位置的标签引用,offset 是一个21位的有符号偏移量。下面是一个使用 ADRP 指令的简单例子:

ADRP X0, LABEL  // 加载标签LABEL的地址到X0寄存器
 
LABEL:
    MOV X1, X0  // 将LABEL的地址移动到X1

在这个例子中,ADRP 用于加载标签 LABEL 的地址到寄存器 X0。注意,ADRP 仅用于页对齐的地址,并且只能加载到64位寄存器中。如果需要非对齐地址或更精确的加载,你可能需要结合使用 ADR 或其他内存加载指令。

 

补充:

adrp <寄存器>,<立即数>, 作用是把pc寄存器跟立即数按照一定规则计算后赋值给寄存器。这个规则就是将pc指针的低12bit清0,然后加上<立即数>左移12bit后的值,将结果赋值给<寄存器>

adrp x8,1 //等效与 x8 = pc & ~0xfff + 1<<12

 

9. arm64汇编 ldr指令

LDR 是 ARM 汇编中的一个 load register 指令,用于将数据从内存中加载到寄存器中。对于 ARM64 汇编,LDR 指令有多种变体,用于处理不同的数据加载和地址计算需求。

以下是一些使用 ARM64 汇编语言中 LDR 指令的示例:

将一个常量加载到寄存器中:

ldr x0, [0x12345678] // 将内存地址 0x12345678 处的值加载到寄存器 x0 中
将一个地址处的值加载到寄存器中,该地址是另一个寄存器的偏移量:

ldr x0, [x1, #0x10] // 将内存地址为 x1 寄存器值加上 0x10 的地址处的值加载到 x0 寄存器中
将一个符号地址处的值加载到寄存器中:

ldr x0, LABEL // 将标签 LABEL 表示的地址处的值加载到 x0 寄存器中
// ...
LABEL:
.quad 0x12345678 // 一些数据
将一个地址处的值加载到寄存器中,该地址是另一个寄存器的值与一个常数的和:

ldr x0, [x1, #0x10]! // 将内存地址为 x1 寄存器值加上 0x10 的地址处的值加载到 x0 寄存器中,同时将新地址写回到 x1 寄存器
使用 LDR 指令加载一个函数指针到寄存器中:

ldr x16, .LPIC0 // 加载一个 PIC (Position Independent Code) 偏移量到 x16 寄存器
// ...
.LPIC0:
.quad LPIC-.-
在使用 LDR 指令时,确保你的操作数和操作对应的寄存器是兼容的,并且考虑到 ARM64 寄存器的命名规则。此外,还需要注意指令的字节序和对齐问题。

举例:

LDR R0, [R1]    //R1寄存器对应地址的数据被取出放入R0
LDR R0, =NAME   //R0寄存器的值将为NAME标号对应的地址。
LDR R0, =0X123  //R0寄存器的值将为立即数的值

 

10. Arm64汇编 bl 指令

bl 是 ARM 汇编语言中的一个跳转指令,用于调用子程序。bl 指令在跳转到子程序前会将下一条指令的地址保存在链接寄存器(LR)中,这样子程序在返回时可以正确继续执行。

bl 指令的格式如下:bl <target_label>

其中 <target_label> 是你想要跳转到的子程序的标签。

例如,假设你有一个子程序 my_subroutine,你可以使用 bl 指令从另一个标签(比如 my_label)调用它:

my_label:
    ...
    bl my_subroutine
    ...
 
my_subroutine:
    ...
    mov x0, #0  @ 返回0
    ret         @ 返回到bl指令后续指令

在这个例子中,当执行到 bl my_subroutine 时,执行流会跳转到 my_subroutine,并保存 my_label 后面的指令地址以便返回。当 my_subroutine 执行完毕并使用 ret 指令返回时,执行流会回到保存在 LR 中的地址继续执行。

 

11. arm64汇编 stp 指令

stp 是 ARM 汇编语言中的一个指令,用于将一组寄存器的值存储到内存中。stp 是 "Store Registers in Pair" 的缩写。

语法:

stp { xn | sp }, { xn | sp }, [r], {#imm}

参数:

{ xn | sp } 是一个寄存器,可以是 x30(通常是 lr 或链接寄存器)或 sp(堆栈指针)。
{ xn | sp } 是另一个寄存器,用于与第一个寄存器配对。
[r] 是目标内存地址的基地址寄存器。
{#imm} 是一个可选的偏移量,用于指定存储位置的具体偏移量。

示例代码:

stp x29, x30, [sp, -16]! // 将 x29 和 x30 压栈,并更新 sp 的值

在这个例子中,stp 指令将寄存器 x29 和 x30 的值存储到当前堆栈顶部,然后将堆栈顶部向下移动 16 字节,并更新堆栈指针 sp。后缀 ! 表示对寄存器 sp 进行修改。######


12. arm64汇编 b.ne 指令

b.ne 是 ARM 汇编语言中的一个条件分支指令,它的全称是 "Branch if Not Equal",也就是当两个操作数不相等时才会跳转。

这个指令通常用于比较两个寄存器或者寄存器和立即数的值,然后根据比较结果是否相等来决定是否跳转到另一个标签(Label)或者指定的地址。

下面是一个使用 b.ne 指令的简单例子:

cmp x0, x1 // 比较寄存器x0和x1的值
b.ne label // 如果不相等,跳转到标签label处执行

在这个例子中,cmp 指令用于设置条件标志位,根据 x0 和 x1 的值进行比较。b.ne 指令检查不相等(NE)标志位,如果该标志被设置(表示x0不等于x1),则执行跳转到标签 label。

需要注意的是,b.ne 是一个短跳转指令,它的跳转范围是有限的,通常在当前指令的后面或者前面128MB范围内。#######如果需要更远的跳转,你应该使用 b 指令或其他分支指令。


13. arm64汇编 cmp 指令

CMP 是 ARM 汇编语言中的一个指令,用于比较两个操作数。当两个操作数作减法时,如果 Minuend(被减数)大于 Subtrahend(减数),则结果为正;如果 Minuend(被减数)小于 Subtrahend(减数),则结果为负;如果两者相等,结果为零。

CMP 指令不会改变操作数本身,只会设置一些特殊的程序状态寄存器(PSR)的标志位,这些标志位可以用来决定接下来应该执行什么样的代码分支。

下面是一些使用 CMP 指令的例子:

(1) 基本的比较操作:

cmp r0, r1 @ 将寄存器 r0 的值和 r1 的值进行比较

(2) 比较立即数:

cmp r0, #0 @ 将寄存器 r0 的值和立即数 0 进行比较

(3) 比较并根据结果决定是否跳转:

cmp r0, r1
beq next @ 如果 r0 等于 r1,则跳转到标签 next 的指令

(4) 比较数组中的元素:

ldr r2, [r0], #4 @ 加载数组的下一个元素到 r2
cmp r2, r1 @ 将 r2 和 r1 进行比较
bne difference @ 如果 r2 和 r1 不相等,则跳转到标签 difference 的指令

注意:CMP 指令不会改变操作数本身,只会改变状态寄存器的标志位。如果你需要保留操作数用于其他目的,你应该在执行 CMP 指令后将操作数拷贝到另一个寄存器。


14. Arm64汇编 dc 指令

在ARM架构中,DC是一个用于数据复制的指令,通常用于初始化数据。DC指令是ARM汇编器的扩展,用于在ELF (Executable and Linkable Format) 文件中生成一个专用的 .data.rel.ro 节。

DC指令的语法如下:

DC <constant> ; 复制一个常量到寄存器
DC { <constant_expression> } ; 复制一个常量表达式到寄存器
DC { <symbol> } ; 复制一个符号的地址到寄存器
DC { :<alignment> } ; 设置下一个数据标签的对齐
DC { ^ } ; 结束数据标签的定义
例如,以下是一个使用DC指令的简单ARM64汇编代码片段:

.data
.align 3
my_data:
DC 42 ; 将常量42初始化到一个字
DC 23 ; 将常量23初始化到下一个字
DC {my_symbol} ; 将符号my_symbol的地址初始化到一个字
DC {^} ; 结束数据初始化

在这个例子中,my_data 被初始化为包含四个字,分别是42, 23, my_symbol的地址,和一个结束标记。这种初始化方法通常用于初始化数组或者其他数据结构。


15. Arm64汇编 adr_l 指令

ADR_P 是 ARM 汇编器的一个指令,用于生成相对于 PC 的地址。它是 ADR 指令的一个变种,用于处理大于 4KB 的加载。

ADR_P 指令的语法如下:

ADR_P <register>, <expression>

其中 <register> 是目标寄存器,<expression> 是目标地址。

这个指令会尝试生成一个有效的地址,但是如果目标地址超出了 ADR_P 指令的有效范围(即,目标地址与当前 PC 的偏移量超过了 2^12 - 1 字节),那么这个指令将失败。

例如,如果你有一个标签 .label 在 4KB 之后,你可以使用 ADR_P 来加载它的地址:

adrp x0, .label
add x0, x0, :lo12:.label

这里,adrp 用于获取 .label 的高 32 位地址,add 用于获取低 12 位的偏移量。

注意:ADR_P 是在 ARMv8-A 架构中引入的,因此它不能在不支持此功能的旧架构中使用。


16. Arm64汇编 mov_q 指令

movq 是一个用于64位操作数的指令,用于将数据从一个位置移动到另一个位置。


17. arm64汇编 ret 指令

在ARM架构中,ret 指令用于从子程序返回到调用者。在ARMv8-A (arm64) 汇编中,ret 指令可以用于从子程序返回并恢复程序状态。

ret 指令的基本语法如下:

ret{cond}

其中 {cond} 是可选的条件代码。如果不指定,则默认条件代码为 al (即所有条件码)。

下面是一个简单的例子,展示了如何在ARM64汇编中使用 ret 指令:

sub sp, sp, #0x20 // 分配栈空间
stp x29, x30, [sp, #0x10]! // 保存调用者的链接寄存器和程序计数器
// ...子程序代码 ...
ldp x29, x30, [sp], #0x20 // 恢复调用者的链接寄存器和程序计数器
ret // 返回到调用者

在这个例子中,我们在调用子程序前保存了链接寄存器 x29 (fp) 和程序计数器 x30 (lr),在子程序结束前恢复它们,并使用 ret 指令返回到调用者。


18. Arm64汇编 ldp 指令

ldp 是 ARM 汇编语言中用于从寄存器组或栈中加载双精度浮点寄存器(FP Double-precision)的指令。它用于从内存地址加载 128 位的数据到两个浮点寄存器(通常是单独的浮点寄存器,但也可以是一个的高 64 位和另一个的低 64 位)。

语法如下:

LDP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>
LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!
LDP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>
LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!

这里 <Wt1> 和 <Wt2> 是目标浮点寄存器,<Xn|SP> 是基址寄存器,<imm> 是一个常量偏移量。

例子:

ldp x29, x30, [sp], #0x20 // 将栈上偏移为 sp 的 32 字节处的数据加载到 x29 和 x30,然后 sp 增加 0x20

在这个例子中,ldp 指令用于从当前的栈指针 sp 所指向的位置加载两个 64 位的值到浮点寄存器 x29 和 x30,然后更新栈指针 sp 增加 0x20 字节。


19. Arm64汇编 ENTRY 指令

在ARM架构的汇编语言中,ENTRY 是一个宏指令,用于定义一个符号的入口点,即该符号是程序的入口或者开始点。在ARM64汇编语言中,通常用于定义一个函数的开始。下面是一个简单的ARM64汇编语言示例,展示了如何使用ENTRY指令定义一个函数的入口点:

// 定义一个名为my_function的函数
ENTRY(my_function)
// 函数的实现代码
mov x0, #0 // 将返回值设置为0
ret // 函数返回
END(my_function)

在这个例子中,ENTRY(my_function)定义了一个名为my_function的函数入口点,而END(my_function)表示该函数的结束。在这两个指令之间,是函数的具体实现代码。


20. Arm64汇编 .quad 指令

.quad 是 ARM 汇编器(如 GNU 汇编器,GAS)中用于定义一个 64 位的常数的指令。例如,如果你想在数据段中定义一个 64 位的常数,你可以这样做:

.data
my_constant:
    .quad 0x123456789abcdef0

如果你想在未初始化数据段中为一个变量预留空间,你可以这样做:

.bss
my_variable:
    .quad 0

注意:.quad 指令只能用于定义数据,不能用于定义代码。如果你想在代码段中定义一个 64 位的值,你应该使用 .code64 指令开启 64 位代码模式,然后使用适当的指令来定义值。


21. Arm64汇编 .section 指令

.section 是 GAS 汇编器(GNU Assembler)中用来定义段(section)的指令。在 ELF 格式的目标文件中,段是文件的一部分,它包含了特定类型的数据。在 ARM 汇编中,.section 指令用来定义自定义的段,以便在链接时包含在最终的可执行文件中。

例如,在 ARM 汇编代码中,你可能会看到如下的段定义:

.section .data, "aw", @progbits

这行代码定义了一个名为 .data 的段,该段包含已初始化的数据。其中,参数的含义如下:

"aw": 指定段的访问权限和类型。a 表示段可以自动增长,w 表示段是可写的。

@progbits:指定段中的数据是程序的一部分,应当被链接器复制到输出文件中。

在实际应用中,你可以定义自己的段来组织代码,例如:

.section my_section
my_global_symbol:
    mov x0, #1
    ret

在这个例子中,my_section 是自定义的段名称,my_global_symbol 是一个全局的标号,它可以在其他的汇编文件中引用。

需要注意的是,.section 指令只是定义了段的开始,如果你想要在段的末尾有明确的界限,你可能需要使用 .section 的变体,如 .text 用于定义代码段,.data 用于定义初始化的数据段等


22. Arm64汇编 blr 指令

带返回的跳转指令,跳转到指令后边跟随寄存器中保存的地址(例:blr x8; 跳转到x8保存的地址中去执行)

 

23. bne 1b 和 beq 1f

1:
   ldr r4,[r2],#4
   str r4,[r1],#4
   cmp r1,r3
   bne 1b

bne 1b 这条语句的意思是向后跳转到标签1处,这里的b是backward的意思,既然有backward就有forward,所有就有bne 1f语句:

1: //A
cmp r0, #0
beq 1f  //r0==0那么向前跳转到B处执行,而不是A处
bne 1b  //否则向后跳转到A处执行
1: //B

 

二、语法

1. 宏定义

汇编中宏定义是以 .macro 开头,以 .endm 结尾。宏定义中以  \x 来引用宏定义中的参数 x

2. 输出到指定的段中

.pushsection和.popsection是GNU汇编器(GAS)的指令,用于改变当前的段(section)。这对于在编写跨平台的代码或者需要动态控制代码段布局时非常有用。.pushsection用于将当前段添加到栈中,并开始使用新的段。.popsection用于从栈中移除最后一个添加的段,并可选地开始使用新的段。

例如,在ARM64汇编中,你可能会这样使用它们:

.section .data
data_section_start:
    .word 0x12345678
 
.section .text
.global _start
_start:
    adr x0, data_section_start
    ldr x1, [x0]
    ...
 
.pushsection .data
    .word 0x87654321
.popsection

在这个例子中,我们首先定义了一个.data段,其中包含一些初始化的数据。然后我们定义了一个.text段,其中包含程序的入口点_start。在_start中,我们使用adr指令获取到data_section_start标签的地址,并使用ldr指令从该地址加载数据。

接下来,我们使用.pushsection和.popsection来动态地改变当前的段。我们将新的数据(0x87654321)推送到.data段中,并在使用完成后通过.popsection指令将段恢复到之前的状态。

这种技术在处理复杂的数据段和代码段布局时非常有用,可以让你更灵活地控制输出的二进制文件。

例如linux内核中的 .idmap.text 段的填充:

//arch/arm64/kernel/sleep.S
.text
.pushsection ".idmap.text", "awx"
XXX
.popsection

//arch/arm64/kernel/cpu-reset.S
.text
.pushsection    .idmap.text, "awx"
XXX
.popsection
//arch/arm64/kvm/hyp-init.S
.text
.pushsection    .hyp.idmap.text, "ax"
XXX
.popsection

验证是否的确在段中:

//arch/arm64/kernel/head.S
.section ".idmap.text","awx"  //line 477
XXX
.pushsection ".mmuoff.data.write", "aw" //line 674
YYY
.popsection //line 692

从477行开始不包括 674--692行中定义的函数有:
kimage_vaddr
el2_setup
set_cpu_boot_mode_flag
secondary_holding_pen
secondary_entry
secondary_startup
__secondary_switched
__secondary_too_slow
__enable_mmu
__cpu_secondary_check52bitva
...
这些函数 cat /proc/kallsyms 看,都在 __idmap_text_start 和 __idmap_text_end 之间。674--692行中的 __boot_cpu_mode 则不在区间内。

 

三、示例

1. 复杂指令

str \tmp2, [\tbl, \tmp1, lsl #3] //翻译成C就是 *((long *)(tbl + (tmp1 << 3))) = tmp2;

 

posted on 2024-07-10 09:21  Hello-World3  阅读(10)  评论(0编辑  收藏  举报

导航