x86 常见调用约定(cdecl,fastcall,stdcall) & x86和ARM调用约定的栈帧分析 & ARM ATPCS(ARM-THUMB procedure call standard)
PS:要转载请注明出处,本人版权所有。
PS: 这个只是基于《我自己》的理解,
如果和你的原则及想法相冲突,请谅解,勿喷。
前置说明
本文作为本人csdn blog的主站的备份。(BlogID=053)
本文发布于 2018-01-18 11:29:39,现用MarkDown+图床做备份更新。blog原图已丢失,使用csdn所存的图进行更新。(BlogID=053)
环境说明
X86:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5)
ARM:gcc version 4.8.3 20131202 (prerelease) (Hisilicon_v400)
前言
由于某些工作的需要,我需要掌握X86以及ARM的一些调用规则,让自己可以大致看懂ASM代码。于是,我总结了一下我需要的东西。
调用约定有啥用?
对于现在习惯使用高级程序的人来说,这一切都是闲的蛋疼才会去看这些,不止浪费时间,还浪费表情。但对于有需求使用ASM+C或者C艹的混合编程或者纯ASM编程的时候,这就得注意这些了。因为这代表着你的目标能否成功的问题。
x86 常见调用以及对应的栈帧分析
cdecl用在C/C++,MFC的默认方式, 可变参数
//cdecl
extern "C"
int __attribute__((cdecl)) Func2(int a, int b, int c, int d, int e, int f){
int aa;
int bb;
int cc;
int dd;
aa = bb = cc= dd = a;
return 0;
}
@调用子程序过程
pushl $6
pushl $5
pushl $4
pushl $3
pushl $2
pushl $1
call Func2
@call,eip入栈,跳转到子程序
addl $24, %esp
@esp-24,清空临时栈
@子程序过程
.LFE1021:
.size Func1, .-Func1
.globl Func2
.type Func2, @function
Func2:
.LFB1022:
.cfi_startproc
pushl %ebp
@ebp入栈
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
@esp赋值给ebp
.cfi_def_cfa_register 5
subl $16, %esp
@注意,虽然上面esp减16是由于有4个4byte的局部变量,但是如果不是4个局部变量,此版本的编译器是按照16byte*N(N取大于0的整数)来分配的局部栈。列如:3个4byte变量,局部栈大小是16bytes,5个4byte变量,局部栈大小为32bytes,其他类似方式分配,不要看不懂为啥多分配了,或者少分配了。
movl 8(%ebp), %eax
@a 赋值给eax
movl %eax, -16(%ebp)
@ eax 赋值给dd
movl -16(%ebp), %eax
movl %eax, -12(%ebp)
movl -12(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, -4(%ebp)
movl $0, %eax
@返回值放在eax
leave
@leave = mov ebp,esp 以及 pop ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
@pop eip
.cfi_endproc
说明:按从右至左的顺序压参数入栈,由调用者把参数弹出栈。
对子程序分析:其他详见注释。具体栈帧分布图,见下图:
stdcall,Win API
extern "C"
int __attribute__((stdcall)) Func3(int a, int b, int c, int d, int e, int f){
int aa;
int bb;
int cc;
aa = bb = cc;
return 0;
}
pushl $6
pushl $5
pushl $4
pushl $3
pushl $2
pushl $1
call Func3
.LFE1022:
.size Func2, .-Func2
.globl Func3
.type Func3, @function
Func3:
.LFB1023:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $16, %esp
movl -12(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, -4(%ebp)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret $24
@pop eip , subl 24,esp
.cfi_endproc
说明:按从右至左的顺序压参数入栈,由被调用者从栈中弹出参数。
其他参考见上文。
fastcall,要求速度快
extern "C"
int __attribute__((fastcall)) Func4(int a, int b, int c, int d, int e, int f){
int aa;
int bb;
int cc;
aa = bb = cc;
return 0;
}
pushl $6
pushl $5
pushl $4
pushl $3
movl $2, %edx
movl $1, %ecx
call Func4
.LFE1023:
.size Func3, .-Func3
.globl Func4
.type Func4, @function
Func4:
.LFB1024:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $24, %esp
movl %ecx, -20(%ebp)
movl %edx, -24(%ebp)
movl -12(%ebp), %eax
movl %eax, -8(%ebp)
movl -8(%ebp), %eax
movl %eax, -4(%ebp)
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret $16
.cfi_endproc
说明:按从右至左的顺序压参数入栈,参数1,参数2通过ecx,edx传递,由被调用者从栈中弹出参数。
其他参考见上文。
ARM ATPCS
extern "C"
int Func1(int a, int b, int c, int d, int e, int f){
int aa;
int bb;
int cc;
int dd;
int ee;
aa = bb = cc= dd = ee = a;
return 0;
}
mov r3, #5
str r3, [sp]
mov r3, #6
str r3, [sp, #4]
mov r0, #1
mov r1, #2
mov r2, #3
mov r3, #4
bl Func1
.text
.align 2
.global Func1
.type Func1, %function
Func1:
.fnstart
.LFB971:
@ args = 8, pretend = 0, frame = 40
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #44
str r0, [fp, #-32]
str r1, [fp, #-36]
str r2, [fp, #-40]
str r3, [fp, #-44]
ldr r3, [fp, #-32]
str r3, [fp, #-8]
ldr r3, [fp, #-8]
str r3, [fp, #-12]
ldr r3, [fp, #-12]
str r3, [fp, #-16]
ldr r3, [fp, #-16]
str r3, [fp, #-20]
ldr r3, [fp, #-20]
str r3, [fp, #-24]
mov r3, #0
mov r0, r3
sub sp, fp, #0
@ sp needed
ldr fp, [sp], #4
bx lr
.cantunwind
.fnend
分析:
r15 PC The Program Counter.
r14 LR The Link Register.
r13 SP The Stack Pointer.
r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
R11 可选,被称为FP,即frame pointer。
其他分析见下图:
特别说明:此图保留区域写错了,对于此编译器来说,应该是4个4bytes*N(N大于0的整数)的分配本地变量的方式
后记
无
参考文献
- 无
打赏、订阅、收藏、丢香蕉、硬币,请关注公众号(攻城狮的搬砖之路)
PS: 请尊重原创,不喜勿喷。
PS: 要转载请注明出处,本人版权所有。
PS: 有问题请留言,看到后我会第一时间回复。
x86 常见调用约定(cdecl,fastcall,stdcall) & x86和ARM调用约定的栈帧分析 & ARM ATPCS(ARM-THUMB procedure call standard)的更多相关文章
- 关于调用约定(cdecl、fastcall、、thiscall) 的一点知识(用汇编来解释)good
函数调用规范 当高级语言函数被编译成机器码时,有一个问题就必须解决:因为CPU没有办法知道一个函数调用需要多少个.什么样的参数.即计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者 ...
- 第5篇-调用Java方法后弹出栈帧及处理返回结果
在前一篇 第4篇-JVM终于开始调用Java主类的main()方法啦 介绍了通过callq调用entry point,不过我们并没有看完generate_call_stub()函数的实现.接下来在ge ...
- Don’t Use Accessor Methods in Initializer Methods and dealloc 【初始化和dealloc方法中不要调用属性的存取方法,而要直接调用 _实例变量】
1.问题: 在dealloc方法中使用[self.xxx release]和[xxx release]的区别? 用Xcode的Analyze分析我的Project,会列出一堆如下的提示:Inco ...
- ios调用第三方程序打开文件,以及第三方调用自己的APP打开文件
1.自己的APP调用第三方打开文件 主要是使用 UIDocumentInteractionController 类 并实现 UIDocumentInteractionControllerDel ...
- C与Lua互相调用的时候,栈变化分析
1 C调用Lua函数的堆栈变化 例子 Lua文件中的函数 function testNewCounter2() return "第四个结果" end C中的例子 void t_n ...
- C++构造函数的自动调用(调用一个父类的构造函数,有显性调用最好,否则就默认调用无参数的构造函数)——哲学思想:不调用怎么初始化父类的成员数据和VMT?
我总是记不住构造函数的特点,关键还是没有领会那个哲学思想:父类的构造函数一方面要初始化它自己的成员数据,另一方面也要建立它自己的VMT呀!心里默念一百遍:一定调用父类构造函数,一定调用父类构造函数,一 ...
- dedecms列表页调用子栏目列表,织梦首页调用栏目的子栏目标签代码
dedecms列表页调用子栏目列表,织梦首页调用栏目的子栏目标签代码. dedecms列表页调用子栏目列表标签: {dede:channelartlist type='sun' }<a href ...
- Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)
当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...
- [Android Pro] 深入理解函数的调用过程——栈帧
cp :http://blog.csdn.net/x_perseverance/article/details/78897637 每一个函数被调用时,都会为函数开辟一块空间,这块空间就称为栈帧. 首先 ...
- python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值
三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...
随机推荐
- Java并发(七)----线程sleep、yield、线程优先级
1.sleep 与 yield sleep 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞) 其它线程可以使用 interrupt 方法打断正在睡眠的线 ...
- 《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)
第 6 章 高级查询和日志 6.1 分页 在 EF Core 中,数据的查询通过集成语言查询(LINQ)实现,它支持强类型,支持对 DbContext 派生类的 DbSet 类型成员进行访问,DbSe ...
- .NET Core 在 K8S 上的开发实践--学习笔记
摘要 本主题受众是架构师,开发人员,互联网企业 IT 运维人员.大纲:1. K8S 对应用的要求:2. .NET Core 上 K8S 的优势:3. K8S 下的 .NET Core 配置:4. .N ...
- NC54580 素数分布
题目链接 题目 题目描述 素数分布函数 \(\pi (n)\) 表示小于或等于n的素数的数目.例如 \(\pi (10)=4\)(2,3,5,7是素数).这个函数涉及到许多高等数论的内容,甚至和黎曼猜 ...
- NC204871 求和
题目链接 题目 题目描述 已知有 \(n\) 个节点,有 \(n-1\) 条边,形成一个树的结构. 给定一个根节点 \(k\) ,每个节点都有一个权值,节点i的权值为 \(v_i\) . 给 \(m\ ...
- Vue中data为何以函数形式返回
data为何以函数形式返回 在使用Vue构建组件化应用时,每个组件的data属性都是以函数形式返回的,这主要是在组件化实现的时候,每个实例可以维护一份被返回对象的独立的拷贝,而不是共享同一个对象的引用 ...
- flex布局-20201028
改版自阮一峰的网络日志-Flex 布局教程:语法篇 在flex容器上设置的(即父元素上设置); flex-direction属性决定主轴的方向(即项目的排列方向). flex-direction: r ...
- 前后端分离解决跨域cors问题
修改windows的hosts文件 vim C:\Windows\System32\drivers\etc\hosts 添加域名 前端:www.luffycity.cn 后端:api.luffycit ...
- Ubuntu防火墙相关
查看防火墙当前状态 sudo ufw status 开启防火墙 sudo ufw enable 关闭防火墙 sudo ufw disable 查看防火墙版本 sudo ufw version 默认允许 ...
- 【Azure API 管理】讨论APIM是否适合直接存储文件到Azure Storage Account呢?
问题描述 需要从 APIM 直接将大文件存入Azure Storage,没看到这方面的官方文档,所以是否有这方面的实践案例,或者APIM是否支持引用SDK (如Azure Storage SDK)? ...