惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V2EX - 技术
V2EX - 技术
P
Privacy International News Feed
Security Latest
Security Latest
H
Hacker News: Front Page
T
Tenable Blog
The Hacker News
The Hacker News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Security @ Cisco Blogs
Project Zero
Project Zero
O
OpenAI News
AI
AI
Spread Privacy
Spread Privacy
C
CERT Recently Published Vulnerability Notes
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Scott Helme
Scott Helme
Application and Cybersecurity Blog
Application and Cybersecurity Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
CXSECURITY Database RSS Feed - CXSecurity.com
NISL@THU
NISL@THU
A
Arctic Wolf
T
Threat Research - Cisco Blogs
PCI Perspectives
PCI Perspectives
N
News and Events Feed by Topic
C
Cyber Attacks, Cyber Crime and Cyber Security
C
Cybersecurity and Infrastructure Security Agency CISA
Simon Willison's Weblog
Simon Willison's Weblog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
Google Online Security Blog
Google Online Security Blog
罗磊的独立博客
L
LINUX DO - 最新话题
U
Unit 42
S
Security Affairs
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
博客园 - 【当耐特】
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
月光博客
月光博客
Engineering at Meta
Engineering at Meta
腾讯CDC
F
Full Disclosure
Cyberwarzone
Cyberwarzone
S
SegmentFault 最新的问题
Recorded Future
Recorded Future
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 司徒正美
The Cloudflare Blog

博客园 - woodfish

偏序集的Dilworth定理 XJOJ历经2个月终于完成啦~~ fork()调用的一个趣题 实现google那种输入框提示的功能 POJ 3691 安徽第二题 有限状态自动机+DP 哈尔滨赛区网络预选赛总结 [计算几何]点集中的点能组成多少个正方形 [计算几何]POJ 1375 点对圆的切线+线段重叠 [计算几何]POJ 1556 判断线段相交+Dijkstra [计算几何] POJ 1873 暴力+凸包 [计算几何]POJ 1266 三角形的外接圆 圆的参数方程 POJ 1026 置换群 [计算几何]POJ 1031 计算点对多边形的偏转角度 [计算几何]POJ2079 求点集中面积最大的三角形 [计算几何]POJ3608 求2个不相交凸包的最短距离 [计算几何]凸包的旋转卡壳算法 C++禁止一个类被继承的技术 计算位数的3种方法 避免使用条件分支
C与汇编的接口技术
woodfish · 2008-03-01 · via 博客园 - woodfish

1.保存寄存器
  首先,C假定子程序保存了下面这几个寄存器的值:EBX,ESI,EDI,EBP,CS,DS,SS,ES。这并不意味着不能在子程序内部修改他们。相反,它表示如果子程序改变了它们的值,那么子程序返回之前必须恢复它们的原始值。EBX,ESI和EDI的值不能被改变,因为C将这些寄存器用于寄存器变量。通常都是使用堆栈来保存这些寄存器的原始值。

2.函数名
  大多数C编译器都在函数名和全局或静态变量前附加一个下划线字符。例如,函数名f将指定为_f,而不是f。Linux gcc编译器并不附加任何字符。在可执行的Linux ELF下,对于C函数f,你只需要简单使用函数名f即可。但是,DJGPP的gcc却附加了一个下划线。

3.传递参数
  按照C调用约定,一个函数的参数将以一定顺序压入栈中,这个顺序与他们出现在函数里的顺序相反。
  考虑这条C语句:printf("x=%d\n",x);下图上展示了如何编译这条语句(用等价的NASM格式)。下图下展示了执行完printf函数的开始部分后,堆栈的状态。printf函数是一个可以携带任意个参数的C语言库函数。C调用约定的规则就是专门为允许这些类型的函数而规定的。因为format字符串最后压入堆栈,所以不管有多少参数传递到函数,它在堆栈里的位置将总是EBP+8。然后printf代码就可以通过看format字符串的位置来决定需要传递多少参数和堆栈上如何找到它们。
  当然,如果有错误发生,printf("x=%d\n"),printf代码仍然会将[EBP+12]中的双字输出,而这并不是x的值。

segment .data
x        dd    
0
format   db    
"x=%d\n",0

segment .text

    
push dword [x]    ;将x的值压入栈中
    push dword format ;将format字符串的地址压入栈中
    call _printf      ;注意下划线!
    add esp,8         ;从栈中移除参数


4.计算局部变量的地址
  找到定义在data或bss段的变量地址是非常容易的。基本上,连接程序做的就是这件事情。但是,要计算出在堆栈上的一个局部变量(或参数)的地址就不简单了。可是,当调用子程序时,这种需求是非常普通的。考虑传递一个变量(让我们称它为x)的地址到一个函数(让我们称它为foo)的情况。如果x处在堆栈的EBP-8的位置,你不可以这样使用:
mov  eax,ebp-8
为什么?因为指令MOV储存到EAX里的值必须能有汇编器计算出来(也就是说,它最后必须是一个常量)。但是,有一条指令能做这种需求。它就是LEA(Load Effective Address)。下面的代码就能计算出x的地址并将它储存到EAX中:
lead  eax,[ebp-8]
现在EAX中有了x的地址,而且当调用函数foo的时候,就可以将其压入到栈中。

5.返回值
    返回值不为空的C函数执行完后会返回一个值。C调用约定规定了这个要如何去做。返回值需要通过寄存器传递。所有的整形类型(char,int,enum等)通过EAX寄存器返回。如果他们小于32位,那么储存到EAX的时候,他们将被扩展成32位。64位的值通过EDX:EAX寄存器对返回。浮点数出巡在数学协处理器的ST0寄存器中。

6.其它调用约定
    所有的80x86 C编译器中都支持上面描述的标准C调用约定的规则。通常编译器也支持其它调用约定。挡雨汇编语言进行接口时,知道编译器调用你的函数时使用的是什么调用约定是非常重要的。通常,缺省时,使用的是标准的调用约定;但是,并不总是这一种情况。使用多种约定的编译器都拥有可以用来改变缺省约定的命令行开关。他们同样提供扩展的C语法来为单个函数指定调用约定。但是,各个编译器的这些扩展标准可以是不一样的。
    GCC编译器允许不同的调用约定。一个函数的调用约定可以通过扩展语法__attribute__明确指定。例如,要声明一个返回值为空的函数f,它带有一个int参数,使用标准调用约定,需要使用下面的语法来声明它的圆形:
    void f(int)  __attribute__((cdecl));
GCC同样支持标准call调用约定。通过把cdecl替换成stdcall,上面的函数可以指定为使用这种约定。stdcall约定和cdecl约定的不同点是stdcall要求子程序将参数移除栈(和Pascal调用约定一样)。因此,stdcall调用约定只能使用在带有固定参数的函数上。
    Borland和Microsoft使用一样语法来声明调用约定。他们在C代码中加上关键字_cdecl和_stdcall。这些关键字来修饰函数。在原型声明中,他们出现在函数名的前面:
       void _cdecl f(int);
    每种调用约定都有自己的优缺点。cdecl调用约定的主要有点是它非常简单而且灵活。它可以用于任何类型的C函数和C编译器。使用其它约定会限制子程序的可移植性。他的主要缺点是与其他约定相比它的执行较慢而且使用更多的内存。
    stdcall调用约定的主要优点是相比于cdecl它使用较少的内存。在CALL指令之后,不需要清理堆栈。它的主要缺点是它不能用于可变参数的函数。