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. Markdown Rules 详解

    使用VSCode编写Markdown文件时,建议安装插件markdownlint,它可以帮助自己更加规范的写文章. 下面是所有的markdown语法错误信息以便纠错. Rules文档 Markdown ...

  2. IIS的详细配置

    一:配置默认文档 输入ip打开哪个页面是由默认文档设定的 1.打开IIS配置页面,点击网站.我们的默认站点已经启动,可以看到绑定的ip和网页的路径 2.选中Default Web Site,可以看到有 ...

  3. 树莓派安装freeswitch

    树莓派版本: Raspberry Pi 4B 操作系统 : Ubuntu Server 20.04_x64 freeswitch版本 : 1.10.3 1.下载freeswitch源代码 wget h ...

  4. 鹏程杯子2023 pwn

    主要就是修改stdin的最后几位,使他变为write,然后泄露libc,为所欲为即可. 本人是卡在不知道stdin那里可以修改. 然后使用一下jmp qword rbp这个gadget 0x400a9 ...

  5. C++文件输入输出的简单实现(Debug)

    1.前言: 文件输入输出是个很有用的东西,有时比赛时要有:要求使用文件输入输出,还有时候-- 遇到这种时间限制非常恶心的题目:手动测试会有误差-- 文件输入输出是个很好的选择! 2.写法: C C语言 ...

  6. Power BI 6 DAY

    Power BI 数据建模与数据汇总分析 层级关系 跨表取字段时类型二可用 父子级关系条件 一个父级下对应多个子级值 一个子级值只属于一个父级 跨表取字段的条件:维度连接用关键字段间是父子级关系时,可 ...

  7. react 快速接入 sentry,性能监控与错误上报踩坑日记

    壹 ❀ 引 本文是我入职第一个月所写,在主导基建组的这段时间也难免会与错误监控和性能监控打交道,因为公司主要考虑接入sentry,所以对于接入sentry的基建任务也提了一些需求,主要分为: 支持查看 ...

  8. PyOCD Notes

    Installation Ubuntu20.04 For Ubuntu20.04 the version in apt repository is 0.13.1+dfsg-1, which is to ...

  9. 大数运算(BigInteger)与进制转换

    1 前言 Java 提供了 BigInteger(大整数)类和 BigDecimal(大浮点数)类用于大数运算,这两个类都继承自 Number 类(抽象类).由于 BigInteger 在大数运算中更 ...

  10. Js实用小技巧

    Js实用小技巧 这是一份Js实用小技巧,也可以是一份Js挨打小技巧,下面的一系列操作虽然能够在一定程度上使代码更加简洁,但是在缺少注释的情况下会降低可读性,所以需要谨慎使用这些黑魔法. 位元算 取整 ...