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)的更多相关文章

  1. 关于调用约定(cdecl、fastcall、、thiscall) 的一点知识(用汇编来解释)good

    函数调用规范   当高级语言函数被编译成机器码时,有一个问题就必须解决:因为CPU没有办法知道一个函数调用需要多少个.什么样的参数.即计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者 ...

  2. 第5篇-调用Java方法后弹出栈帧及处理返回结果

    在前一篇 第4篇-JVM终于开始调用Java主类的main()方法啦 介绍了通过callq调用entry point,不过我们并没有看完generate_call_stub()函数的实现.接下来在ge ...

  3. Don’t Use Accessor Methods in Initializer Methods and dealloc 【初始化和dealloc方法中不要调用属性的存取方法,而要直接调用 _实例变量】

    1.问题:    在dealloc方法中使用[self.xxx release]和[xxx release]的区别? 用Xcode的Analyze分析我的Project,会列出一堆如下的提示:Inco ...

  4. ios调用第三方程序打开文件,以及第三方调用自己的APP打开文件

    1.自己的APP调用第三方打开文件 主要是使用  UIDocumentInteractionController  类   并实现 UIDocumentInteractionControllerDel ...

  5. C与Lua互相调用的时候,栈变化分析

    1  C调用Lua函数的堆栈变化 例子 Lua文件中的函数 function testNewCounter2() return "第四个结果" end C中的例子 void t_n ...

  6. C++构造函数的自动调用(调用一个父类的构造函数,有显性调用最好,否则就默认调用无参数的构造函数)——哲学思想:不调用怎么初始化父类的成员数据和VMT?

    我总是记不住构造函数的特点,关键还是没有领会那个哲学思想:父类的构造函数一方面要初始化它自己的成员数据,另一方面也要建立它自己的VMT呀!心里默念一百遍:一定调用父类构造函数,一定调用父类构造函数,一 ...

  7. dedecms列表页调用子栏目列表,织梦首页调用栏目的子栏目标签代码

    dedecms列表页调用子栏目列表,织梦首页调用栏目的子栏目标签代码. dedecms列表页调用子栏目列表标签: {dede:channelartlist type='sun' }<a href ...

  8. Spring MVC普通类或工具类中调用service报空空指针的解决办法(调用service报java.lang.NullPointerException)

    当我们在非Controller类中应用service的方法是会报空指针,如图: 这是因为Spring MVC普通类或工具类中调用service报空null的解决办法(调用service报java.la ...

  9. [Android Pro] 深入理解函数的调用过程——栈帧

    cp :http://blog.csdn.net/x_perseverance/article/details/78897637 每一个函数被调用时,都会为函数开辟一块空间,这块空间就称为栈帧. 首先 ...

  10. python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值

    三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...

随机推荐

  1. Java并发(七)----线程sleep、yield、线程优先级

    1.sleep 与 yield sleep 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞) 其它线程可以使用 interrupt 方法打断正在睡眠的线 ...

  2. 《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)

    第 6 章 高级查询和日志 6.1 分页 在 EF Core 中,数据的查询通过集成语言查询(LINQ)实现,它支持强类型,支持对 DbContext 派生类的 DbSet 类型成员进行访问,DbSe ...

  3. .NET Core 在 K8S 上的开发实践--学习笔记

    摘要 本主题受众是架构师,开发人员,互联网企业 IT 运维人员.大纲:1. K8S 对应用的要求:2. .NET Core 上 K8S 的优势:3. K8S 下的 .NET Core 配置:4. .N ...

  4. NC54580 素数分布

    题目链接 题目 题目描述 素数分布函数 \(\pi (n)\) 表示小于或等于n的素数的数目.例如 \(\pi (10)=4\)(2,3,5,7是素数).这个函数涉及到许多高等数论的内容,甚至和黎曼猜 ...

  5. NC204871 求和

    题目链接 题目 题目描述 已知有 \(n\) 个节点,有 \(n-1\) 条边,形成一个树的结构. 给定一个根节点 \(k\) ,每个节点都有一个权值,节点i的权值为 \(v_i\) . 给 \(m\ ...

  6. Vue中data为何以函数形式返回

    data为何以函数形式返回 在使用Vue构建组件化应用时,每个组件的data属性都是以函数形式返回的,这主要是在组件化实现的时候,每个实例可以维护一份被返回对象的独立的拷贝,而不是共享同一个对象的引用 ...

  7. flex布局-20201028

    改版自阮一峰的网络日志-Flex 布局教程:语法篇 在flex容器上设置的(即父元素上设置); flex-direction属性决定主轴的方向(即项目的排列方向). flex-direction: r ...

  8. 前后端分离解决跨域cors问题

    修改windows的hosts文件 vim C:\Windows\System32\drivers\etc\hosts 添加域名 前端:www.luffycity.cn 后端:api.luffycit ...

  9. Ubuntu防火墙相关

    查看防火墙当前状态 sudo ufw status 开启防火墙 sudo ufw enable 关闭防火墙 sudo ufw disable 查看防火墙版本 sudo ufw version 默认允许 ...

  10. 【Azure API 管理】讨论APIM是否适合直接存储文件到Azure Storage Account呢?

    问题描述 需要从 APIM 直接将大文件存入Azure Storage,没看到这方面的官方文档,所以是否有这方面的实践案例,或者APIM是否支持引用SDK (如Azure Storage SDK)? ...