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