您的位置:首页 > 其它

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

2014-07-27 16:33 525 查看
    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 cal
a838
l. 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.

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  abi x86 汇编函数