x86的ABI(C函数实现原理)分析

This article is aim to explain how to use assemble language realize those common function

in C. But I fail to get a simple method to introduce it because of some reasons . I will try to

extract some key point at this article. Then analysize a example in detail in next article.

( Of course, For those experienced guys, maybe a example is enough.)

1. How can we create local variable in a function?

/**

*    How can we create local variable in a function?

*

*    This is a interesting problem. First at all, what is the essence of a variable ?

*        The answer is space,memory space. Recall the reason that we introduced the concept of

*    the variable .we need those space to save some information. So,in fact, create a variable is

*    equal to allocate some space.

*

*        Now, the question is we should reside those variable in where ?

*    Actually, we has been know something about global variable and static variable. They are

*    arranged when compiled. But what about local variable ? where is it reside in ?

*        Obviously,we can‘t arrange a special memory space for it when compile. Think about

*    recursive function. If we specify a special memory space for a local variable, how can we

*    ensure a function is reentrant. That will be awful, totally awful. So the conclusion is we

*    can‘t reside the local variable in a absolute address, no matter where. It should be reside

*    in a relative address. If we build a base address for every function call, then every function

*    call will become independent. That is what we want theoretically. Actually, How can we

*    build that frame ?

*

*        Now, it is time to introduce a important design -- stack frame. It is helpful to realize

*    our plan above. two special register, esp and ebp, was introduced to build a frame for a

*    function. In addition, it provide a nice solution for function call, too.

*

*        the emphasis of this frame is stack. It is building down. %ebp was used to point to

*    the bottom of the frame .%esp was used to point to the top of frame. That means if we

*    build a function like this:

*            int func()

*            {

*                ....

*            }

*

*    we will get a frame like this

*            0xbfffe6a0    <-- %ebp

*            ....

*            0xbfffe690    <-- %esp

*

*    if there are some local variable in the function, just like this:

*            int func( )

*            {

*                int a, b, c;

*            }

*

*    the frame maybe:

*            0xbfffe6a0    <-- %ebp

*            0xbfffe69c    <-- c, 4 bytes

*            0xbfffe698    <-- b, 4 bytes

*            0xbfffe694    <-- a, 4 bytes

*                               <-- %esp

*

*    we have been know how to create some local variable in assemble language.

*/

2. How can we call a function ?

/*

*    How can we call a function ?

*

*        This seems like simple. From the view of machine, call a function is equal to change the

*    flow of instructions, is equal to revise the value of register %IP.

*            mov func,ip;

*

*        but how can we return the caller ? maybe save the value of IP before revise is necessary

*    . It seems we have two choice : save in a register, or save in the memory. Think about the

*    current situation, register is still finite, and function call is infinite logically. So the memory

*    will be a good choice.

*

*        But where should be the place for those IP informations ? I thought we could allocate

*    some memory space to build a special structure. It is used to save those information. Actually,

*    a better way was introduced. see the following example, if we call a subroutine in main

*    function:

*            int main()

*            {

*                fun();

*            }

*            void fun()

*            {

*                ...

*            }

*

*

*        The value of pre-IP will be push into the stack and register %IP will be revise to the

*    entry of fun function. the information will be saved like this.

*            0xbfffe6a0 <-- %ebp for main()

*            0xbfffe69c <-- var 2

*            0xbfffe698 <-- var 1

*            0xbfffe694 <-- var 0

*            ....

*            xxxxxxxx   <-- return address

*                           <-- %esp for main()

*

*    when we finish this subroutine, we could return the caller by pop the value into register %IP.

*/

3. How can we pass parameters between caller and callee ?

/**

*    How can we pass parameters between caller and callee ?

*

*        In C language, it is common to transmit data between caller and callee. How can we

*    realize it in assemble language ? Need to say, every function call should have a independent

*    parameters list, because we need our function is reentrant. see this example:

*            int main()

*            {

*                fun(1,2,3);

*            }

*            int fun(int a, int b, int c)

*            {

*

*            }

*

*        before we call fun(). The stack frame of main is :

*            0xbbbb00ff <-- %ebp for main

*            ....            <-- variables

*            ....            <-- %esp for main

*

*

*        when we call this function, the following steps will be done.

*        First at all, Push the parameters into the stack,

*            0xbbbb00ff  <-- %ebp for main

*            ....             <-- variables

*            0xbbbb00ec <-- 3, the last parameter

*            0xbbbb00e8 <-- 2, the second parameter

*            0xbbbb00e4 <-- 1, the first parameter

*                           <-- %esp for main

*

*        then push the return address of caller,

*            0xbbbb00ff  <-- %ebp for main

*            ....             <-- variables

*            0xbbbb00ec <-- 3, the last parameter

*            0xbbbb00e8 <-- 2, the second parameter

*            0xbbbb00e4 <-- 1, the first parameter

*            0xbbbb00e0 <-- return address of caller

*                              <-- %esp for main

*

*        then jump to the function. It will build a new stack frame for this call. But before that,

*    we need to save the information of caller frame.Because we will recover the frame of caller

*    when we finish this subroutine. The frame is :

*            0xbbbb00ff  <-- the base address of main frame

*            ....             <-- variables

*            0xbbbb00ec <-- 3, the last parameter

*            0xbbbb00e8 <-- 2, the second parameter

*            0xbbbb00e4 <-- 1, the first parameter

*            0xbbbb00e0 <-- return address of caller

*                              <-- the top address of main frame

*                            <-- %ebp for fun

*            0xbbbb00dc <-- the value of %ebp of main.

*            ....             <-- variables

*                            <-- %esp for fun

*

*    Based on those steps, we build a new frame for callee.

*/

x86的ABI(C函数实现原理)分析,布布扣,bubuko.com

时间: 2024-10-14 11:32:04

x86的ABI(C函数实现原理)分析的相关文章

【转载】Select函数实现原理分析

Select函数实现原理分析 <原文> select需要驱动程序的支持,驱动程序实现fops内的poll函数.select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用(如可读或写),如果有的话则返回可用资源的文件描述符个数,没有的话则睡眠,等待有资源变为可用时再被唤醒继续执行. 下面我们分两个过程来分析select: 1. select的睡眠过程 支持阻塞操作的设备驱动通常会实现一组自身的等待队列如读/写等待队列用于支持上层(用户层)所需的BLOCK(阻塞)或NONBLO

x86的ABI分析(函数实现原理)--part2

As we all know, function is a important concept in programming design. At this moment, I even don't know what kind of programming language can working without function. ( maybe i am new). maybe some special language can ? But this concept is very nec

android脱壳之DexExtractor原理分析[zhuan]

http://www.cnblogs.com/jiaoxiake/p/6818786.html内容如下 导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1.  需要动态调试 2.  对抗反调试方案 为了提高工作效率, 我们不希望把宝贵的时间浪费去和加固的安全工程师去做对抗.作为一个高效率的逆向分析师, 笔者是忍不了的,所以我今天给大家带来一种的新的脱壳方法——DexExtractor脱壳法. 资源地址: Dex

android脱壳之DexExtractor原理分析

导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1.  需要动态调试 2.  对抗反调试方案 为了提高工作效率, 我们不希望把宝贵的时间浪费去和加固的安全工程师去做对抗.作为一个高效率的逆向分析师, 笔者是忍不了的,所以我今天给大家带来一种的新的脱壳方法--DexExtractor脱壳法. 资源地址: DexExtractor源码:https://github.com/bunnyblue/DexExtracto

Linux 下函数栈帧分析

1.关于栈 对于程序,编译器会对其分配一段内存,在逻辑上可以分为代码段,数据段,堆,栈 代码段:保存程序文本,指令指针EIP就是指向代码段,可读可执行不可写 数据段:保存初始化的全局变量和静态变量,可读可写不可执行 BSS:未初始化的全局变量和静态变量 堆(Heap):动态分配内存,向地址增大的方向增长,可读可写可执行 栈(Stack):存放局部变量,函数参数,当前状态,函数调用信息等,向地址减小的方向增长,非常非常重要,可读可写可执行.如下图所示: 首先必须明确一点也是非常重要的一点,栈是向下

kafka producer实例及原理分析

1.前言 首先,描述下应用场景: 假设,公司有一款游戏,需要做行为统计分析,数据的源头来自日志,由于用户行为非常多,导致日志量非常大.将日志数据插入数据库然后再进行分析,已经满足不了.最好的办法是存日志,然后通过对日志的分析,计算出有用的数据.我们采用kafka这种分布式日志系统来实现这一过程. 步骤如下: 搭建KAFKA系统运行环境 如果你还没有搭建起来,可以参考我的博客: http://zhangfengzhe.blog.51cto.com/8855103/1556650 设计数据存储格式

Adaboost算法原理分析和实例+代码(简明易懂)

Adaboost算法原理分析和实例+代码(简明易懂) [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时间,才明白他的基本原理.也许是自己能力有限吧,很多资料也是看得懵懵懂懂.网上找了一下关于Adaboost算法原理分析,大都是你复制我,我摘抄你,反正我也搞不清谁是原创.有些资料给出的Adaboost实例,要么是没有代码,要么省略很多步骤,让初学者

Android视图SurfaceView的实现原理分析

附:Android控件TextView的实现原理分析 来源:http://blog.csdn.net/luoshengyang/article/details/8661317 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制.又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输

linux中mmap系统调用原理分析与实现

参考文章:http://blog.csdn.net/shaoguangleo/article/details/5822110 linux中mmap系统调用原理分析与实现 1.mmap系统调用(功能)      void* mmap ( void * addr , size_t len , int prot , int flags ,int fd , off_t offset )      内存映射函数mmap, 负责把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的