Arm64 FP/LR寄存器解析

3460阅读 0评论2021-08-04 静默梧桐
分类:LINUX

ARM64 PCS(procedure Call Stanard)定义:

X29 is the frame pointer register (FP). 用来定位有效的栈帧记录。

X30 is the link register (LR). The branch-and-link instructions that store a return address in the link register (BL and BLR), setting the register X30 to PC+4.  Calls to subroutines, where it is necessary for the return address to be stored in the link register(X30).

link register for subroutine calls is different to the link register for exceptions.


从上图中可以看到一个有效栈帧通用的布局,

“Local variables + callee saved register + 上一栈帧的LR`/FP`”

 

首先来看一下loadstore指令有关的几种寻址模式, 这会帮助理解后面的汇编代码。

Base register


Offset addressing modes

Pre-index addressing modes

Post-index addressing modes:


从实例中看这两个寄存器是如何起作用的.

我们是否可以修改x30寄存器???

写一个汇编代码来定义trampoline_test(),函数返回值为8;

$cat stack_frame.S

#include

#include

#include

        .text

.global trampoline_test

trampoline_test:

        stp     x29, x30, [sp, #-16]!

        mov     x29, sp

        stp     x19, x20, [sp, #-16]!

        stp     x21, x22, [sp, #-16]!

        stp     x25, x26, [sp, #-16]!

        mov     x25, sp

        mov     x26, #0x0

        mov     w7, #0x0

        ldp     x25, x26, [sp], #16

        ldp     x21, x22, [sp], #16

        ldp     x19, x20, [sp], #16

        ldp     x29, x30, [sp], #16

        add     x0,  x7, #0x8    // return 8;

        ret


下面代码执行后,输出为: 208

        i = trampoline_test();

        i = 200;

        i += 8;

        printf("i==%d\n",i);


编译执行:

as -o stack_frame.o stack_frame.S

gcc -c -o jump_test.o  jump_test.c

gcc jump_test.o  stack_frame.o -o jump_test


将代码稍微改动,ret之前将x30+8

$cat stack_frame.S

#include

#include

#include

        .text

.global trampoline_test

trampoline_test:

        stp     x29, x30, [sp, #-16]!

        mov     x29, sp

        stp     x19, x20, [sp, #-16]!

        stp     x21, x22, [sp, #-16]!

        stp     x25, x26, [sp, #-16]!

        mov     x25, sp

        mov     x26, #0x0

        mov     w7, #0x0

        ldp     x25, x26, [sp], #16

        ldp     x21, x22, [sp], #16

        ldp     x19, x20, [sp], #16

        ldp     x29, x30, [sp], #16

        add     x0,  x7, #0x8    // return 8;

        add     x30, x30, #0x8   // 跳过两条指令

        ret


再次编译执行:



从反汇编代码中看到“add  x30, x30, #0x8”正是跳过了“i = 200;”这条语句;

所以最终的执行结果为 i==16.


上一篇:kretprobe: 关于offline module的一个bug
下一篇:Subroutine Call of x86-64