ARM汇编初识

iOS架构及设备

架构 设备 宽度
armv6 iPhone, iPhone2, iPhone3G, 第一代、第二代iPod Touch 32
armv7 iPhone3GS, iPhone4, iPhone4S, iPad, iPad2, iPad3(The New iPad), iPad mini, iPod Touch 3G, iPod Touch4 32
armv7s iPhone5, iPhone5C, iPad4(iPad With Retina Display) 32
arm64 iPhone5s以及之后版本 64

ARM64寄存器

寄存器 描述
x0-x30 通用寄存器, 如果有需要可以当做32bit(w0-w30)使用
FP(x29) 保存栈帧地址(栈底指针)
LR(30) 通常称x30为程序链接寄存器, 保存子程序结束后需要执行的下一条指定的地址
SP 保存栈指针, 使用SP/WSP来进行对SP寄存器的访问
PC 程序计数器, 俗称PC指针, 总是指向即将执行的下一条指令, 在arm64中, 软件是不能改写PC寄存器的
SPSR 状态寄存器
  • x0-x7: 用于传递函数参数, 超出的参数将入栈. 假如在函数funcA中调用函数funcB, 传给funcB的参数超出8个的将保存在函数funcA函数栈的栈顶.
  • x0 - x30 是31个通用整形寄存器。每个寄存器可以存取一个64位大小的数。 当使用 r0 - r30/x0 - x30 访问时,它就是一个64位的数。当使用 w0 - w30 访问时,访问的是这些寄存器的低32位.

寄存器概念补充

数据地址寄存器

数据地址寄存器通常用来做数据计算的临时存储、做累加、计数、地址保存等功能。定义这些寄存器的作用主要是用于在CPU指令中保存操作数,在CPU中当做一些常规变量来使用。

ARM64中
  • 64位: X0-X30, XZR(零寄存器)
  • 32位: W0-W30, WZR(零寄存器)

注意:
之前讲解8086汇编中有一种特殊的寄存器段寄存器:CS,DS,SS,ES四个寄存器来保存这些段的基地址,这个属于Intel架构CPU中.在ARM中并没有

浮点和向量寄存器

因为浮点数的存储以及其运算的特殊性,CPU中专门提供浮点数寄存器来处理浮点数

  • 浮点寄存器 64位: D0 - D31 32位: S0 - S31

SP和FP寄存器

  • sp寄存器在任意时刻都会保存我们栈顶的地址
  • fp寄存器也称为x29寄存器属于通用寄存器, 但是在某些时刻我们利用它保存栈底地址

注意: ARM64开始, 取消32位的LDM,STM,PUSH,PHP指令, 取而代之的是ldr/ldp,str/stp
ARM64里面对栈的操作是16字节对齐的

关于内存读写指令

注意: 读/写数据都是往高地址读/写

str(store register)

将数据从寄存器存到栈中, 同时操作两个寄存器时, 使用stp

str x0,[sp,#0x10]

ldr(load register)

将数据从栈读到寄存器中, 同时操作两个寄存器时, 使用ldp

ldr x0,[sp,#0x10]

堆栈操作练习

将32个字节空间作为这段程序的栈空间,然后利用栈x0,x1的值进行交换

sub sp,sp,#0x20                  ;拉伸栈空间
stp x0,x1,[sp,#0x10]             ;将x0,x1存放在sp+0x10为地址的栈中
ldp x1,x0,[sp,#0x10]             ;从sp+0x10为地址的栈中读取数据到x1,x0
add sp,sp,#0x20                  ;平栈

bl和ret指令

bl 标号

  • 将下一条指令的地址放入lr(x30)寄存器 (l)
  • 跳转执行标号为地址所指向的指令 (b)

ret

  • 默认使用lr(x30)寄存器的值, 通过底层指令提示CPU此处作为下一条指令的地址!

ARM64平台的特色指令, 它面向硬件做了优化处理

x30寄存器(lr)

  • x30寄存器存放的是函数的返回地址. 当ret指令执行时, 会寻找x30寄存器保存的地址所指向的内存保存的值为下一条指令

注意: 在函数嵌套调用的时候. 需要将x30入栈!

ldp    x29, x30, [sp, #0x10]
add    sp, sp, #0x20             ; =0x20 
ret

函数的参数和返回值

  • ARM64下, 函数的参数是存放在x0-x7(w0-w7)这8个寄存器里面的. 如果超过8个参数, 就会入栈.
  • 函数的返回值放在x0寄存器里面

NZCV状态寄存器

  • CPU内部的寄存器中, 有一种特殊的寄存器(对于不同处理器, 个数和结构可能不同). 这种寄存器在RAM中, 被称为CPSR(Current program status register)寄存器
  • CPSR和其他寄存器不同, 其他寄存器是用来存放数据的, 都是整个寄存器具有一个含义. 而CPSR寄存器是按位起作用的, 它的每一位都有特定含义.
  • CPSR的低八位(包括I、F、T、M[4:0]) 称为控制位, 程序无法修改, 除非CPU运行于特权模式下.
  • N、Z、C、V均为条件标志位. 他们的内容可被算数或逻辑运算改变, 并且可以决定某条指令是否被执行(if的汇编实现..)

注: CPSR是32位寄存器. add/sub等指令不能影响CPSR寄存器, 如需要保存计算状态, 使用adds/subs等.

N(Negative)

CPSR的第31位(从零开始数...)是N, 符号标志位. 它记录相关指令执行后, 其结果是否为负. 如果结果为负, N=1. 反之N=0.

Z(Zero)

CPSR的第30位(...你们懂得)是Z, 0标志位,. 它记录相关指令执行后, 其结果是否为0, 如果是0, Z=1. 反之Z=0.

C(Carry)

CPSR的第29位(...)时C, 进位标志位. 一般情况下, 进行无符号数运算.
加法运算: 当运算产生进位时, C=1, 反之C=0.
减法运算(包括CMP): 当运算产生借位时, C=0, 反之C=1.

  • 可理解为, 进位将进位的1保存到了C. 借位将C保存的1借走. 而实际上, 借位之前C为保存的不一定是1. 进位也类似(未仔细求证).
进位: 
mov w0,#0xaaaaaaaa;0xa 的二进制是 1010
adds w0,w0,w0; 执行后 相当于 1010 << 1 进位1(无符号溢出) 所以C标记 为 1
adds w0,w0,w0; 执行后 相当于 0101 << 1 进位0(无符号没溢出) 所以C标记 为 0
adds w0,w0,w0; 重复上面操作
adds w0,w0,w0
借位:
mov w0,#0x0
subs w0,w0,#0xff ;
subs w0,w0,#0xff
subs w0,w0,#0xff

V(Overflow) 溢出标志

CPSR的第28位时V, 溢出标志位. 在进行有符号运算时, 如果超过了机器所能标识的范围, 视为溢出.

实际是无符号运算影响了符号位或者产生了进位或借位

以下情况都会造成溢出
  • 正数 + 正数 = 负数
  • 负数 + 负数 = 正数

正数 + 负数 不可能溢出.

指令条件码(逻辑对照)

竟然跟NZCV对应的值不匹配, 虽然理解, 但还是好难受.
比如不相等, 就不能确定N位的值. 猜测

编码 助记符 描述 标记
0000 EQ (equal) 相等 Z=1
0001 NE(Not Equal) 不相等 Z=0
0010 CS/(Carry Set/High or Same) 无符号数大于/等于 C = 1
0011 CC/LO(Carry Clear/LOwer) 无符号数小于 C = 0
0100 MI(MInus) 负数 N=1
0101 PL(PLus) 非负数 N=0
0110 VS(oVerflow set) 上溢出 V=1
0111 VC(oVerflow clear) 没有上溢出 V=0
1000 HI(HIgh) 无符号数大于 C=1 且 Z=0
1001 LS(Lower or Same) 无符号数小于/等于 C=0 且 Z=1
1010 GE(Greater or Equal) 有符号数大于或等于 N=V
1011 LT(Less Than) 有符号数小于 N!=V
1100 GT(Greater Than) 有符号数大于 Z=0,N=V
1101 LE(Less or Equal) 有符号数小于等于 Z=1,N!=V
1110 AL 无条件执行 任何
1111 NV 从不执行 任何

全局变量/静态变量/常量

  • 全局变量、静态变量保存在静态区
  • 常量的话, 如果是字符串, 通常保存在常量区. 较大(二进制表示需要较大宽度)的数字类型保存在常量区. 如果是较小数字, 可以通过立即数的形式来保存.
  • 较大的数字(ARM64中二进制表示大于0xffff, 即长度超过2字节), 因为ARM汇编命令是等长的(四字节), 比较大的数不能包含在命令中, ARM通过偏移的方式, 使用adrp指令读取静态区.
  • 同理字符串也不能保存在代码区, 通过偏移的方式, 同样使用adrp指令读取.

下面代码是读取一个常量/静态变量到x8寄存器

adrp x0,1        ; 将当前PC寄存器指向的地址低12位清零, 加上 (`1`左移12位), 将结果保存到`x0`寄存器
add x0,#0xf28    ; `x0`保存的值加上偏移0xf28再次保存到`x0`寄存器.
ldr x8, [x0]     ; 将x0存储的值作为地址, 读取地址指向的数据, 保存到x8寄存器

上面代码中, 最后x8寄存器保存的就是一个静态变量或者字符串常量的指针.

待续

// 知识有限, 随时修改..

// ## #### ######

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容