基础语法、汇编初探
Swift版本
- 历时5年发展,从Swift1.x发展到了Swift5.x版本,经历了多次重大改变,ABI终于稳定
- API(Application Programming Interface):应用程序编程接口
- 源代码和库之间的接口
- ABI(Application Binary Interface):应用程序二进制接口
-
应用程序与操作系统之间的底层接口
-
涉及的内容有:目标文件格式、数据类型的大小\布局\对齐、函数调用约定等等
-
- API(Application Programming Interface):应用程序编程接口
- 随着ABI的稳定,Swift语法基本不会再有太大的变动,此时正是学习Swift的最佳时刻
-
截止至2019年6月,目前最新版本:Swift5.1
- Swift完全开源: https://github.com/apple/swift,主要采用C++编写
- swiftc存放在Xcode内部
- Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
- 一些操作
- 生成语法树: swiftc -dump-ast main.swift
- 生成最简洁的SIL代码:swiftc -emit-sil main.swift
- 生成LLVM IR代码: swiftc -emit-ir main.swift -o main.ll
- 生成汇编代码: swiftc -emit-assembly main.swift -o main.s
- 对汇编代码进行分析,可以真正掌握编程语言的本质
- 编译流程如下:

程序的本质
- 软件\程序的执行过程

寄存器与内存
-
通常,CPU会先将内存中的数据存储到寄存器中,然后再对寄存器中的数据进行运算
-
假设内存中有块红色内存空间的值是3,现在想把它的值加1,并将结果存储到蓝色内存空间
- CPU首先会将红色内存空间的值放到rax寄存器中:
movq 红色内存空间, %rax - 然后让rax寄存器与1相加:
addq $0x1, %rax - 最后将值赋值给内存空间:
movq %rax, 蓝色内存空间

- CPU首先会将红色内存空间的值放到rax寄存器中:
编程语言的发展
- 机器语言
- 由0和1组成
- 汇编语言(Assembly Language)
- 用符号代替了0和1,比机器语言便于阅读和记忆
- 高级语言
- C\C++\Java\JavaScript\Python等,更接近人类自然语言
- 操作:将寄存器BX的内容送入寄存器AX
- 机器语言:1000100111011000
- 汇编语言:movw %bx, %ax
- 高级语言:ax = bx;
编程语言的发展

- 汇编语言与机器语言一一对应,每一条机器指令都有与之对应的汇编指令
- 汇编语言可以通过编译得到机器语言,机器语言可以通过反汇编得到汇编语言
- 高级语言可以通过编译得到汇编语言 \ 机器语言,但汇编语言 \ 机器语言几乎不可能还原成高级语言
汇编语言的种类
-
汇编语言的种类
-
8086汇编(16bit)
-
x86汇编(32bit)
-
x64汇编(64bit)
-
ARM汇编(嵌入式、移动设备)
-
……
-
x86、x64汇编根据编译器的不同,有2种书写格式
- Intel:Windows派系
- AT&T :Unix派系
-
作为iOS开发工程师,最主要的汇编语言是
- AT&T汇编 -> iOS模拟器
- ARM汇编 -> iOS真机设备
常见汇编指令

小括号代表里面装的是内存地址
-ox18(%rbp) 意思是 %rbp-0x18
movq -ox18(%rbp), %rax
mov是将内存空间存储的地址对应的值取出来,赋值给rax,q代表单位(8个字节)
leaq -0x18(%rbp), %rax
lea是直接算出地址将地址赋值给rax
jump跳转,跳转以后不回头
call跳转到指定地址执行代码,后面跟函数地址,一般跟ret配合使用,ret后回到call后的下一个地址
call *%rax 函数地址存储在rax中,记得加*
rip存储的是指令的地址
CPU要执行的下一条指令地址就存储在rip中
寄存器
-
有16个常用寄存器
-
rax、rbx、rcx 、rdx、rsi、rdi、rbp、rsp
-
r8、r9、r10、r11、r12、r13、r14、r15
-
-
寄存器的具体用途
- rax、rdx常作为函数返回值使用
- rdi、rsi、rdx、rcx、r8、r9等寄存器常用于存放函数参数
- rsp、rbp用于栈操作
- rip作为指令指针
- 存储着CPU下一条要执行的指令的地址
- 一旦CPU读取一条指令,rip会自动指向下一条指令(存储下一条指令的地址)

ah high 高位
al low 低位
r开头:64位,8个字节
e开头:32位,4个字节
ax,bx,cx : 16位,2字节
ah,al : 8位,1字节
bh bl
规律
- 内存地址格式为:0x4bdc(%rip),一般是全局变量,全局区(数据段)
- 内存地址格式为:-0x78(%rbp),一般是局部变量,栈空间
- 内存地址格式为:0x10(%rax),一般是堆空间
lldb常用指令
-
读取寄存器的值
-
register read/格式
-
register read/x
-
-
修改寄存器的值
-
register write 寄存器名称 数值
-
register write rax 0
-
-
读取内存中的值
-
x/数量-格式-字节大小 内存地址
-
x/3xw 0x0000010
-
-
修改内存中的值
-
memory write 内存地址 数值
-
memory write 0x0000010 10
-
-
格式
- x是16进制,f是浮点,d是十进制
-
字节大小
-
b – byte 1字节
-
h – half word 2字节
-
w – word 4字节
-
g – giant word 8字节
-
-
expression 表达式
-
可以简写:expr 表达式
-
expression $rax
-
expression $rax = 1
-
po 表达式
-
print 表达式
- po/x $rax
- po (int)$rax
-
thread step-over、next、n
- 单步运⾏,把子函数当做整体⼀一步执行(源码级别)
-
thread step-in、step、s
- 单步运⾏,遇到子函数会进入子函数(源码级别)
-
thread step-inst-over、nexti、ni
- 单步运行,把子函数当做整体⼀一步执行(汇编级别)
-
thread step-inst、stepi、si
-
单步运⾏,遇到子函数会进入子函数(汇编级别)
-
thread step-out、finish
- 直接执⾏完当前函数的所有代码,返回到上一个函数(遇到断点会卡住)
规律
-
内存地址格式为:
0x4bdc(%rip),一般是全局变量,全局区(数据段) -
内存地址格式为:
-0x78(%rbp),一般是局部变量,栈空间 -
内存地址格式为:
0x10(%rax),一般是堆空间
基础语法
Hello World
- 不用编写main函数,Swift将全局范围内的首句可执行代码作为程序入口
- 一句代码尾部可以省略分号(;),多句代码写到同一行时必须用分号(;)隔开
- 用var定义变量,let定义常量,编译器能自动推断出变量\常量的类型
- Playground可以快速预览代码效果,是学习语法的好帮手
- Command + Shift + Enter:运行整个Playground
- Shift + Enter:运行截止到某一行代码
Playground - View

Playground - ViewController

Playground – 多Page

注释
- Playground的注释支持markup语法(与markdown相似)
- 开启markup渲染效果:Editor -> Show Rendered Markup
- 注意:Markup只在Playground中有效
//单行注释
/*
多行注释
*/
/*
1
/* 多行注释的嵌套 */
2
*/
//: 开始markup
/* :
开始markup
*/
常量
-
只能赋值1次
-
它的值不要求在编译时期确定,但使用之前必须赋值1次

-
下面代码是错误的

-
常量、变量在初始化之前,都不能使用

标识符
-
标识符(比如常量名、变量名、函数名)几乎可以使用任何字符
-
标识符不能以数字开头,不能包含空白字符、制表符、箭头等特殊字符

常见数据类型
| 值类型(value type) | 枚举(enum) | Optional |
|---|---|---|
| 结构体(struct) | Bool、Int、Float、Double、Character | |
| String、Array、Dictionary、Set | ||
| 引用类型(reference type) | 类(class) |
- 整数类型:Int8、Int16、Int32、Int64、UInt8、UInt16、UInt32、UInt64
-
在32bit平台,Int等价于Int32;在64bit平台, Int等价于Int64
-
整数的最值:UInt8.max、Int16.min
- 一般情况下,都是直接使用Int即可
- 浮点类型:Float,32位,精度只有6位;Double,64位,精度至少15位
字面量
- 整数和浮点数可以添加额外的零或者添加下划线来增强可读性
- 100_1000、1_000_000.000_000_1、 000123.456
//字符串
let string = "熊熊熊"
//字符(可存储ASCII字符、Unicode字符)
let character: Character = "🐶"
//布尔
let bool = true //取反是false
//整数
let intDecimal = 17 //十进制
let intBinary = 17 //二进制
let intOctal = 17 //八进制
let intHexadecimal = 17 //十六进制
//浮点数
let doubleDecimal = 125.0 //十进制,等价于1.25e2,0.0125等价于1.25e-2
let doubleHexadecimal1 = 0xFp2 //十六进制,意味着15x2^2,相当于十进制的60.0
let doubleHexadecimal2 = 0xFp-2 //十六进制,意味着15x2^-2,相当于十进制的3.75
//数组
let array = [1, 3, 5, 7, 9]
//字典
let dictionary = ["age" : 18, "height" : 168, "weight" : 120]
类型转换
//整数转换
let int1: UInt16 = 2_000
let int2: UInt8 = 1
let int3 = int1 + UInt16(int2)
//整数、浮点数转换
let int = 3
let double = 0.14159
let pi = Double(int) + double
let intPi = Int(pi)
元祖
let http404Error = (404, "Not Found")
print("The status code is \(http404Error.0)")
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
let (justTheStatusCode, _) = http404Error
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")