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. 部署19c ADG过程中的问题处理

    回忆起来也是有些年没亲自动手搭建ADG了,今天正好有个机会重温,客户环境是19.16,恍惚记得上一次搭ADG还是在11.2.0.4的时代,时光荏苒啊. 正好看下19c的ADG和11g的ADG在部署方面 ...

  2. 23.2 SEH之异常处理--《Windows核心编程》结构化异常处理

    (structured exception handing)SEH 包含终止处理和异常处理.本章讨论异常处理.   当一个硬件或者软件异常被抛出的时候,操作系统会给我们程序一个查看异常类型的机会,并允 ...

  3. Delphi-判断一个对象是否释放,改造官方的Assigned

    直接上例子了,基础知识自己去了解,首先定义一个类: TPerson = class public name: string; age: Integer; constructor Create(name ...

  4. IIS创建和管理虚拟网站

    实验介绍: 本文会详细介绍创建虚拟站点的三种方法 一:IP地址建立站点 1.打开安装了IIS的windows,进入ip配置页面. 添加几个ip,我这里添加的是192.168.1.209,192.168 ...

  5. ARM 中SP,LR,PC寄存器的作用

    ARM中所有寄存器都是32位的.这里以cortex-a7内核的MX6ULL处理器为例,按照功能可以分为两类:运行需要寄存器(程序正常运行所需要的,比如变量暂存,pc制作等,总共43个),系统管理控制寄 ...

  6. Linux操作系统下查询NVMe盘符、Slot ID和Bus ID的对应关系

    在拆卸NVMe PCIe 固态硬盘时,需要查询Linux操作系统下NVMe盘符.Slot ID和Bus ID的对应关系. 操作步骤打开操作系统命令终端.依次执行cd /sys/bus/pci/slot ...

  7. look命令

    look命令 look命令用于查询单词,仅需指定欲查询的字首字符串,它会显示所有开头字符串符合该条件的单词. 语法 look [-bdf] [-t char] string [file ...] 参数 ...

  8. SSH通道

    线下到线上  通过http协议 线上到线下  不能走http,只能通过ssh通道,建立玩ssh通道后,线上线下就可以通道ssh通道进行通信 如:线上为ssm项目  线下为linux项目,二者之间lin ...

  9. Mysql错误消息 语言设置

    今天操作数据库的时候,mysql错误返回语句 ,一直报的是非英语的语言 ,百般纠结 ,简单的还大致能猜出意思 , 复杂了就会实在看不懂的 ,举个简单的如下: [Err] 1064 - Erreur d ...

  10. 我在winform项目里使用“Windows I/O完成端口”的经验分享

    少年!看你骨骼惊奇,是万中无一的练武奇才,我这儿有本武林秘籍,见与你有缘就送你了! 如来神掌 Windows I/O完成端口是一个我至今都说不好的话题,请宽容的接受我这不是科班出身的自学成才的野生程序 ...