`
Ydoing
  • 浏览: 101043 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

(转)详解汇编系统调用过程(以printf为例)

阅读更多

(转)详解汇编系统调用过程(以printf为例)
本文以printf为例,详细解析一个简单的printf调用里头,系统究竟做了什么,各寄存器究竟如何变化。

环境:

linux + gnu as assembler + ld linker

如何在汇编调用glibc的函数?其实也很简单,根据c convention call的规则,参数反向压栈,call,然后结果保存在eax里头。注意,保存的是地址。

在汇编里头,一切皆地址。(别纠结这个,别告诉我还有立即数……主要是要有一切皆地址的思想)

例如这个printf,在C里头,我们用得很多

int printf(const char *format, …) 这里值得一提的是这个“…”是不定参数,也就是说后面有多少个参数,函数定义里头没有规定,感兴趣的可以google一下va_list相关的知识,这里就不展开了。

但是汇编怎么知道处理这个的呢?这里给个简单的解释,感兴趣的可以google一下“c convention call”了解更详细跟专业的解释。

例如当我们调用 result = printf( “%d %d”, 12, a )的时候,编译器默认是这样处理的(除非函数定义声明了pascal call)。

在栈里头,先一次push a的地址,还有12这个立即数,再push “%d %d”这个字符串的地址,内存模型如下,x86的esp是往下增长的。

(这里是buttom,往下增长的是top)

&a

12

address of “%d %d”

——————————————-(esp 指着这里 ,我们假设地址是4字节,12这个数也是4字节)

当call printf的时候,首先,push当前的eip入esp,解析esp+4所指的”%d %d”,因为%d这样的特定字符都定义了后面每个参数的大小,所以只要解析“%d %d”,我们就可以知道栈里头参数的情况,例如esp+4+4就是一个int,esp+4+4+4是另外一个int。

当返回的时候,先pop到eip,也就是把eip还原到call之后马上要执行的机器码,这时,esp就指着“%d %d”,esp+4指着12,esp+8指着a的地址。esp里头的内容怎么处理,看需要吧,你也可以pop出来,也可以不pop。但为了效率着想,如果空间够用,通常不pop,直接用mov指令把下一次要用的参数move进去。返回指储存在eax里头。

这也一定程度上解释了为什么c convention call是反向压栈,这样编译器处理起来方便,特别对于这些va_list,因为va_list后面不能继续跟参数,va_list一定出现在函数的末尾,如果是对printf这类的函数使用pascal call,也就是参数正向压栈,汇编级别处理起来就特别麻烦了。

眼见为实,下面就用汇编写一个调用printf的,并用gdb跟踪寄存器,看看是否是上述的一样。

文件:test_printf.s

.section .data
format: .asciz “%d\n”
.section .text
.global _start
_start:
pushl <nobr><span class="math" id="MathJax-Span-1" style="width: 4.014em; display: inline-block;"><span style="display: inline-block; position: relative; width: 3.255em; height: 0px; font-size: 123%;"><span style="position: absolute; clip: rect(1.412em 1000.003em 2.659em -0.377em); top: -2.274em; left: 0.003em;"><span class="mrow" id="MathJax-Span-2"><span class="mn" id="MathJax-Span-3" style="font-family: MathJax_Main;">12</span><span class="mi" id="MathJax-Span-4" style="font-family: MathJax_Math-italic;">p</span><span class="mi" id="MathJax-Span-5" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-6" style="font-family: MathJax_Math-italic;">s</span><span class="mi" id="MathJax-Span-7" style="font-family: MathJax_Math-italic;">h</span><span class="mi" id="MathJax-Span-8" style="font-family: MathJax_Math-italic;">l</span></span><span style="display: inline-block; width: 0px; height: 2.279em;"></span></span></span><span style="border-left-width: 0.003em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.203em; vertical-align: -0.33em;"></span></span></nobr><script type="math/tex" id="MathJax-Element-1">12 pushl </script>format
call printf
movl $0, (%esp)
call exit

使用如下命令编译,链接

$ as -g test_printf.s -o test_printf.o

$ ld -lc -I /lib/ld-linux.so.2 test_printf.o -o test_printf

as加入-g是要加入调试信息,ld的-lc是链接libc.a,-I是–dynamic-linker,/lib/ld-linux.so.2这个要看各人系统情况。链接libc跟ld库之后,生成test_printf

执行

$ ./test_printf

12

输出12,正常退出。

先用objdump看看test_printf里头的.text section

$ objdump -d test_printf

Disassembly of section .text:

080481c0 <_start>:
80481c0: 6a 0c push <nobr><span class="math" id="MathJax-Span-9" style="width: 15.287em; display: inline-block;"><span style="display: inline-block; position: relative; width: 12.415em; height: 0px; font-size: 123%;"><span style="position: absolute; clip: rect(1.412em 1000.003em 2.659em -0.431em); top: -2.274em; left: 0.003em;"><span class="mrow" id="MathJax-Span-10"><span class="mn" id="MathJax-Span-11" style="font-family: MathJax_Main;">0</span><span class="mi" id="MathJax-Span-12" style="font-family: MathJax_Math-italic;">x</span><span class="mi" id="MathJax-Span-13" style="font-family: MathJax_Math-italic;">c</span><span class="mn" id="MathJax-Span-14" style="font-family: MathJax_Main;">80481</span><span class="mi" id="MathJax-Span-15" style="font-family: MathJax_Math-italic;">c</span><span class="mn" id="MathJax-Span-16" style="font-family: MathJax_Main;">2</span><span class="mo" id="MathJax-Span-17" style="font-family: MathJax_Main; padding-left: 0.274em;">:</span><span class="mn" id="MathJax-Span-18" style="font-family: MathJax_Main; padding-left: 0.274em;">68</span><span class="mi" id="MathJax-Span-19" style="font-family: MathJax_Math-italic;">c</span><span class="mi" id="MathJax-Span-20" style="font-family: MathJax_Math-italic;">c</span><span class="mn" id="MathJax-Span-21" style="font-family: MathJax_Main;">92</span><span class="mn" id="MathJax-Span-22" style="font-family: MathJax_Main;">04</span><span class="mn" id="MathJax-Span-23" style="font-family: MathJax_Main;">08</span><span class="mi" id="MathJax-Span-24" style="font-family: MathJax_Math-italic;">p</span><span class="mi" id="MathJax-Span-25" style="font-family: MathJax_Math-italic;">u</span><span class="mi" id="MathJax-Span-26" style="font-family: MathJax_Math-italic;">s</span><span class="mi" id="MathJax-Span-27" style="font-family: MathJax_Math-italic;">h</span></span><span style="display: inline-block; width: 0px; height: 2.279em;"></span></span></span><span style="border-left-width: 0.003em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.203em; vertical-align: -0.33em;"></span></span></nobr><script type="math/tex" id="MathJax-Element-2">0xc 80481c2: 68 cc 92 04 08 push </script>0x80492cc
80481c7: e8 d4 ff ff ff call 80481a0

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics