第二节 2.2调用约定
<h5>1、参数是如何传入堆栈?</h5>
<h5>2、如何平衡堆栈的?</h5>
<hr />
<hr />
<hr />
<table>
<thead>
<tr>
<th style="text-align: left;">调用约定</th>
<th style="text-align: left;">参数压栈</th>
<th style="text-align: left;">平衡堆栈</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left;"><strong>_cdecl</strong> (C和C++默认的调用约定)</td>
<td style="text-align: left;">从右至左</td>
<td style="text-align: left;">调用者清理</td>
</tr>
<tr>
<td style="text-align: left;"><strong>_stdcall</strong> API使用的调用约定</td>
<td style="text-align: left;">从右至左</td>
<td style="text-align: left;">自身清理</td>
</tr>
<tr>
<td style="text-align: left;">_fastcall</td>
<td style="text-align: left;">ecx/edx传送前两个剩下的从右至左</td>
<td style="text-align: left;">自身清理(只有2个参数,不需要内平栈)</td>
</tr>
</tbody>
</table>
<hr />
<hr />
<h1>_cdecl</h1>
<h4>cdecl(C declaration,即C声明)是源起C语言的一种调用约定,也是C语言的事实上的标准。</h4>
<h4>1.函数<code>实参</code>在线程栈上按照<code>从右至左的顺序依次压栈</code></h4>
<h4>2.函数<code>结果保存在寄存器EAX/AX/AL中</code></h4>
<h4>3.<code>浮点型结果存放在寄存器ST0中</code></h4>
<h4>4.编译后的函数名前缀以一个下划线字符 例:<code>sumExample</code> 编译后:<code>_sumExample</code></h4>
<h4>5.<code>调用者负责</code>从线程栈中弹出实参(即<code>清栈</code>)</h4>
<h4>6.<code>8比特或者16比特长的整形实参提升为32比特长</code></h4>
<h4>7.受到函数调用影响的寄存器(volatile registers):EAX, ECX, EDX, ST0 - ST7, ES, GS</h4>
<h4>8.不受函数调用影响的寄存器: EBX, EBP, ESP, EDI, ESI, CS, DS</h4>
<h4>9.RET指令从函数被调用者返回到调用者(实质上是读取寄存器EBP所指的线程栈之处保存的函数返回地址并加载到IP寄存器)</h4>
<h4>10.堆栈平衡是由调用函数来执行的(在<code>call [地址]</code>,之后会有<code>add esp x</code>,<code>x表示参数的字节数</code>)</h4>
<p><img src="https://www.showdoc.com.cn/server/api/attachment/visitfile/sign/af41d53a682b0b4ac6ee3e5b7d71a598" alt="" /></p>
<hr />
<hr />