......
6.1原生程序ARM汇编语言,逆向你的helloworld
6.2原生程序的生成过程
1:预处理
“如include头文件"包含的头文件全部编译进来,还有#define预定义,#if预条件处理等也都在这里被编译器处,详细的输出可以给gcc编译器传递”-E“,选项查看。
2,编译
编译器首先要检查代码的规范性,以及是有语法错误等,以及代码实际要做的工作,检查无误后,gcc编译器把代码翻译成ARM汇编语言代码,可以为gcc编译器传递”-S“选项查看输出,执行”gcc-s hello.i“ -o hello.s 后生成hello.s汇编文件。
3,汇编
这个阶段会调用连接器将汇编成二进制文件的目标文件,以上一小节的hello为例,执行”gcc-c hello.s -o hello.o“ 后生成hello.o目标文件。
4,连接
这个阶段编译器会调用连接器将二进制的目标文件连接成Android平台可执行的ARM原生程序,以上一个小节为hello为例,执行gcc hello.o -o hello 后会生成hello可执行文件。
6.2.3必须要了解的ARM知识
总结:
1:c语言编写代码在编译时有一个过程,是将其转换成ARM汇编代码,所以可以这么理解,c语言实现的功能ARM
汇编语言都能实现。
2,ARM汇编语言中特有的寄存器。寄存器是处理特有的高速存储部件,它们可以用来暂存指令,数据和位址,高级语言用到中用到的变量,常量,结构体,类等数据用到了ARM汇编语言中,就是使用寄存器保存的值或内存地址,寄存器的数据量有限,ARM微处理器共有37个32位寄存器,其中31个为通用寄存器,6个为状态寄存器,ARM处理器器支持7中运行模式。
1;用户模式(usr)ARM 处理器正常的程序执行状态。
2;快速中断模式(fiq):用与高速数据传输或通道处理
3;外部中断模式(irp)用于通用的中断处理。
4;管理模式(svc)操作系统使用的保护模式
5;数据访问终止模式(abt);当数据或指令预取终止进入该模式,可用于虚拟存储及存储数据。
6;系统模式(sys):运行具有特权的操作系统任务。
7;未定义指令终止模式(und):当未定义的指令执行时进入该模式。
Thumb是ARM体系结构中一种16位的指令集。
从ARMv4T之后的ARM处理器有一种16-bit指令模式,叫做Thumb,也许跟每个条件式执行指令均耗用4位元的情形有关。Thumb 指令集 可以看作是ARM指令压缩形式的子集,它是为减小代码量而提出,具有16bit的代码密度。Thumb指令体系并不完整,只支持通用功能,必要时仍需要使用ARM指令,如进入异常时。其指令的格式与使用方式与ARM指令集类似,而且使用并不频繁,Thumb指令集作一般了解
ARM汇编语言程序结构
1.一个完整的ARM汇编指令包括处理器架构定义,数据段,代码与main函数。
2.段定义.data的数据段中,
如果细分的话,
.rodata的只读数据段中,这些数据段不可以执行的。
.text的代码段中ARM汇编使用,
".section"指令来定义段
.section name
3.注释与标号
/*...*/
4.汇编器指令
程序中所有以“.”开头的指令都是汇编指令,
.file:指定了源文件名,实例hello.s是从hello.c编译得来的,手写汇编代码可以忽略。
.align:指定了代码的对齐方式,后面跟的数值为2的次方,如:“.align4” 表示2^4=16个字节对齐
.ascii:声明全局符号。全局符号是指在本程序外可以访问的符号。
.global:声明全局符号。全局符号是指在本程序外可以访问的符号。
.type:指定符号的类型。“.type main,%function ” 表示main符号为函数。
.word:用来存储地址址。"word. LCD-(LPIC0+8)"存放的是一个与地址无关的偏移量,
.size:设置指定符号的大小。“.size main ,-.main”中的点,“.表示当前地址”,减去main符号的地址即为整个
main符号的地址即为整个main函数的大小。
5.子线程与参数传递
.global 函数名
.type 函数名 ,%function 函数名
函数名
<....函数体...>
例如声明一个实现两个数相加的函数的代码为:
.global MyAdd
.type MyAdd,%function
MyAdd:
ADD:r0, r0,r1 @ 两个数相加
mov pc,lr@函数返回
ARM汇编中规定,R0-R3这4个寄存器用来传递函数调用的第1到第4个参数,超出的参数通过堆栈来传递。R0同时用来存放函数调用的返回值,被调用的函数在返回前无需这些寄存器的内容。
6.4寄存器
1,立即寻址
MOV R0 ,#1234 指令执行后,R0=1234,立即数“#作为前缀",表示十六进制数值时以”0x“开头
2,寄存器寻址
MOV R0 ,R1 寄存器寻址中,操作数的值在寄存器,指令执行时直接从寄存器中取值进行操作
3,寄存器移位寻址
LSL :逻辑左移->移位后寄存器空出的低位补0
LSR:逻辑右移->移位后寄存器空出的高位补0
例如:
MOV
4,寄存器间接寻址
例如:寄存器间接寻址码给出寄存器是操作数的地址指针,所需的操作数保存在寄存器指定地址的存储单元
中,
例如:
LDR
指令功能是将R1寄存器的数值作为地址,取出地址中的值赋值给R0寄存器。
5,基址寻址
基址寻址是将地址码给出的寄存器与偏移量相加,形成操作数的有效地址,所需的操作数保存在有效地址所指向的存储单元中,基址寻址多用于查表,数组访问等操作,
LDR R0 ,[R1,#-4]
指令的功能是 将R1寄存器的数值减4作为地址,取出此地址的值赋值给R0寄存器。
6,多寄存器寻址
多寄存器寻址一条指令最多可以完成16个通用寄存器值得传递
LDMIA
ARM中一个字表示的是一个字的32位数字(bit),这条指令执行后,R1=[R0],R2=[R0+#4]
R3=[R0+#8],R4=[R0+#12]
7,堆栈寻址
堆栈寻址是ARM处理器特有的一种寻址方式,堆栈寻址需要使用特定的指令来完成
由LDMFA/STMFA,LDMEA/STMEA,LDMFD/STMFD
FA,EA,FD,ED,为后缀
堆栈寻址举例:
STMFD SP! {R1-R7,LR} @将R1~R7,LR入栈,多用于保持子线程“现场”
LDMFD SP! {R1-R7,LR} @将数据出栈,放入R1~R7,LR寄存器,恢复子程序“现场”
8,块拷贝寻址
块拷贝寻址可以实现连续地址数据从寄存器的莫某一位置拷贝到另一位置,
块拷贝寻址的指令由
LDMIA/STMIA,LDMDA/STMDA/LDMIB/STMIB
IA,DA,IB,DB
块拷贝举例
LDMIA R0! ,{R1-R3} @从R0寄存器指向的存储单元中读取3个子到R1-R3寄存器
STMIA R0! ,{R1-R3} @存储R1-R3寄存器的内容到R0寄存器指向的存储单元
9,相对寻址
相对寻址以程序计数器PC当前值为级地址,指令中的地址中的标号作为偏移量,将两者相加后得到操作数的有效地址
BL NEXT
...
NEXT :
....
BL NEXT 是跳转到NEXT标号处执行,这里BL采用的就是相对寻址,标号NEXT 就是偏移量。
待续...