ARM64汇编指令入门

一:寄存器:
1.查看寄存器的方式,xcode连接真机,断点后,输入register read可查看arm64所有的寄存器.
有:
x0~x7:传递子程序的参数和返回值,使用时不需要保存,多余的参数用堆栈传递,64位 的返回结果保存在x0中,更多参数用堆栈传递。

x8:用于保存子程序的返回地址,使用时不需要保存。

x9~x15:临时寄存器,也叫可变寄存器,子程序使用时不需要保存。

x16~x17:子程序内部调用寄存器(IPx),使用时不需要保存,尽量不要使用。

x18:平台寄存器,它的使用与平台相关,尽量不要使用。

x19~x28:临时寄存器,子程序使用时必须保存。

x29:帧指针寄存器(FP),用于连接栈帧,使用时必须保存。

x30:链接寄存器(LR),用于保存子程序的返回地址。

x31:堆栈指针寄存器(SP),用于指向每个函数的栈顶。

PC:记录当前CPU当前指令的哪一条指令,存储当前CPU正在执行的指令地址,类似IP

CPSR寄存器:状态标识寄存器,每一位都存着0或1,下面有两张图,说明CPSR寄存器

2.一个寄存器x0代表使用64位空间,而w0代表使用32的空间,X和W代表操作数

二:指令:常用的指令,如果想看到比较全的指令,请百度搜索一下,资料很多
MOV指令:
MOV X1,X0 ;将寄存器R0的值传送到寄存器X1
MOV X1,X2,#0X3 ;将寄存器X2的值与立即数0x3相加后传送到寄存器X1

ADD指令:
ADD X0,X1,X2 ;X0=X1+X2

SUB指令:
SUB X0,X1,X2 ;X0=X1-X2
SUB X0,X1 #256 ;X0=X1-256
SUB X0,X2,X3 LSL#1 ;X0=X2-(X3<<1)

CMP指令:
CMP X0,X1 ;将寄存器x0的值和x1的值相减,并将结果放入cpsr寄存器中
CMP X0,#100 ;将x0的值减去100,放入cpsr中,cpsr寄存器有两位表示(lessthan,zero), 如果结果为小于0,则lessthan这一位标识为1,zero位标识为0

LDR指令:也就是从内存read
LDR X0,[R1] ;将存储地址的R1对应的内存中的值取出并放入X0
LDR X0,[R1,#0x8] ;将R1寄存器中地址加上偏移地址8所对应地址的值取出8个字节存入X0

LDUR指令:和LDR的作用一样,指示偏移地址为正时用LDR,为负时用LDUR
LDUR X0,[R1,#-0x8];

LDP指令:P的意思为pair,为一对
LDP x29, x30, [SP, #0x6] ;栈顶指针偏移6个字节地址后,从这开始,依此取16个字节的值,前8个字节给X29,后8个字节给X30

STR指令:存储指令
STR X8, [X9] ;将X8的值存入X9寄存器所存储的地址的内存中去
STR X8, [X9,#0x8] ;0x8代表偏移地址,和LDR的作用一样

STUR:相对应LDUR,同样是偏移地址为负数使用
STR X8,[X9,#-0x8] ;将X8的值存到X9存储地址-8的位置上去

STP:相对LDP,将一对内容存入内存中
STP x29, x30, [sp, #0x08] ;将X29,X30的值存入偏移8的栈中

B:跳转指令,如条件判断跳转符合条件的指令执行,可以看做是if,else,通常与CMP配合使用
条件域:和B组合在一起,如BEQ(如果相等,则跳转到指令对应的地址)

EQ:相等 NE:不相等 GT:大于 GE:大于等于 LT:小于 LE:小于等于

BL指令:函数调用指令,使用此指令会跳转函数,并将当前下一句指令地址存入LR寄存器
WZR/XZR:零寄存器,里面存储的是0,W开头代表32bit,X开头代表64bit

ORR指令:或

EOR指令:异或

RET指令:子程序返回指令,返回地址默认保存在LR(X30)

三:堆栈平衡:
函数调用过程中,会开辟栈空间供局部变量使用,使用后,需要还原栈空间,FP,指令地址等等
不同的函数的堆栈平衡方式有些不同
1.叶子函数:函数内没有调用其他函数
2.非叶子函数:函数内调用了其他函数

//非叶子函数
test(1,2);
void test(int a,int b)
{
    int x = 5;
    printf("a+b+x=%d",a+b+x);
}

以下代码为执行后的汇编代码

    0x100dd1f08 <+0>:  sub    sp, sp, #0x30             ; 开辟0x30个栈空间
    0x100dd1f0c <+4>:  stp    x29, x30, [sp, #0x20]  ;将原fp地址和返回地址入栈
    0x100dd1f10 <+8>:  add    x29, sp, #0x20            ; 将当前fp寄存器指向sp+0x20的位置
    0x100dd1f14 <+12>: stur   w0, [x29, #-0x4]       ;将寄存器w0=1入栈
    0x100dd1f18 <+16>: stur   w1, [x29, #-0x8]      ;将寄存器w1=2入栈
    0x100dd1f1c <+20>: mov    w8, #0x5                  ;w8寄存器存入5的值
    0x100dd1f20 <+24>: stur   w8, [x29, #-0xc]      ;将5入栈
->  0x100dd1f24 <+28>: ldur   w8, [x29, #-0x4]    ;取出栈中fp-0x4的值放入w8寄存器
    0x100dd1f28 <+32>: ldur   w9, [x29, #-0x8]    ;取出栈中fp-0x8的值放入w9寄存器
    0x100dd1f2c <+36>: add    w8, w8, w9              ;将1+2的结果放入w8
    0x100dd1f30 <+40>: ldur   w9, [x29, #-0xc]    ;取出栈中5的值
    0x100dd1f34 <+44>: add    w10, w8, w9          ;将w8的结果和5相加,放入w10
    0x100dd1f38 <+48>: adrp   x0, 1
    0x100dd1f3c <+52>: add    x0, x0, #0x608            ; =0x608 
    0x100dd1f40 <+56>: mov    x9, sp                      ;将sp的地址放入x9
    0x100dd1f44 <+60>: mov    x8, x10                   ;x10的值放入x8
    0x100dd1f48 <+64>: str    x8, [x9]                     ;将a+b+x的结果入栈
    0x100dd1f4c <+68>: bl     0x100dd2554               ; 调用printf函数
    0x100dd1f50 <+72>: ldp    x29, x30, [sp, #0x20]  ;将之前入栈的fp和返回地址还原
    0x100dd1f54 <+76>: add    sp, sp, #0x30             ; 将栈空间释放
    0x100dd1f58 <+80>: ret                                        ;返回到调用函数的下一句指令


作者:ZZ_军哥
链接:https://www.jianshu.com/p/b6de34ed6942
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/ctbinzi/article/details/127110838