在汇编程序中调用C函数.docVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
在汇编程序中调用C函数

3.4.2? 在汇编程序中调用C函数 从汇编程序中调用C语言函数的方法实际上在上面已经给出。在上面C语言例子对应的汇编程序代码中,我们可以看出汇编程序语句是如何调用swap()函数的。现在我们对调用方法作一总结。 在汇编程序调用一个C函数时,程序需要首先按照逆向顺序把函数参数压入栈中,即函数最后(最右边的)一个参数先入栈,而最左边的第1个参数在最后调用指令之前入栈,如图3-6所示。然后执行CALL指令去执行被调用的函数。在调用函数返回后,程序需要再把先前压入栈中的函数参数清除掉。 ? 调用函数时压入堆栈的参数 在执行CALL指令时,CPU会把CALL指令的下一条指令的地址压入栈中(见图3-6中的EIP)。如果调用还涉及代码特权级变化,那么CPU会进行堆栈切换,并且把当前堆栈指针、段描述符和调用参数压入新堆栈中。由于Linux内核中只使用中断门和陷阱门方式处理特权级变化时的调用情况,并没有使用CALL指令来处理特权级变化的情况,因此这里对特权级变化时的CALL指令使用方式不再进行说明。 汇编中调用C函数比较自由,只要是在栈中适当位置的内容就都可以作为参数供C函数使用。这里仍然以图3-6中具有3个参数的函数调用为例,如果我们没有专门为调用函数func()压入参数就直接调用它的话,那么func()函数仍然会把存放EIP位置以上的栈中其他内容作为自己的参数使用。如果我们为调用func()而仅仅明确地压入了第1、第2个参数,那么func()函数的第3个参数p3就会直接使用p2前的栈中内容。在Linux 0.1x内核代码中就有几处使用了这种方式。例如在kernel/sys_call.s汇编程序中第231行上调用copy_process()函数(kernel/fork.c中第68行)的情况。在汇编程序函数_sys_fork中虽然只把5个参数压入了栈中,但是copy_process()却带有多达17个参数(见下面的程序)。 // kernel/sys_call.s汇编程序_sys_fork部分。 226push %gs 227pushl %esi 228pushl %edi 229pushl %ebp 230pushl %eax 231call _copy_process?# 调用C函数copy_process()(kernel/fork.c,68)。 232addl $20,%esp? ?# 丢弃这里所有压栈内容。 233 1:? ret // kernel/fork.c程序。 68 int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, 69? long ebx,long ecx,long edx, long orig_eax, 70? long fs,long es,long ds, 71 long eip,long cs,long eflags,long esp,long ss) 我们知道,参数越是最后入栈,越是靠近C函数参数左侧。因此实际上调用copy_process()函数之前入栈5个寄存器值就是copy_process()函数的最左面的5个参数。按顺序它们分别对应为入栈的eax(nr)、ebp、edi、esi和寄存器gs的值。而随后的其余参数实际上直接对应堆栈上已有的内容。这些内容是从进入系统调用中断处理过程开始,直到调用本系统调用处理过程时逐步入栈的各寄存器的值。 参数none是sys_call.s程序第99行上利用地址跳转表sys_call_table[](定义在include/linux/ sys.h,93行)调用_sys_fork时的下一条指令的返回地址值。随后的参数是刚进入system_call时在85~91行压入栈的寄存器ebx、ecx、edx、原eax和段寄存器fs、es、ds。最后5个参数是CPU执行中断指令压入返回地址eip和cs、标志寄存器eflags、用户栈地址esp和ss。因为系统调用涉及程序特权级变化,所以CPU会把标志寄存器值和用户栈地址也压入堆栈。在调用C函数copy_process()返回后,_sys_fork也只把自己压入的5个参数丢弃掉,栈中其他值均保存着。其他采用上述用法的函数还有kernel/signal.c中的do_signal()、fs/exec.c中的do_execve()等,请读者自行分析。 另外,我们说汇编程序调用C函数比较自由的另一个原因是我们可以根本不用CALL指令而采用JMP指令来同样达到调用函数的目的。方法是在参数入栈后把下一条要执行的指令地址人工压入栈中,然后直接使用JMP指令跳转到被调用函数开始地址处去执行函数。此后当函数执行完成时就会执行RET指令,把人工压入栈中的下一条指令

文档评论(0)

xy88118 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档