<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[C 0x01(C语言是如何进行函数调用的)]]></title><description><![CDATA[<h2>在上一篇文章中我说错了一件事,其实没有pc寄存器,pc全称是program counter (程序计数器),他是一个抽象的概念,在x86/x64下是ip的数值(也不是很准确,在以后的文章中我们不必纠结这些事情都管他叫做PC)</h2>
<ul>
<li>rbp 寄存器大小</li>
<li>pc 寄存器大小</li>
</ul>
<p dir="auto">在函数调用的时候会在栈中记录下函数调用后下一个指令的地址(pc),还会记录栈基址(rbp),这些数据记录在哪里?肯定就是内存里啦!我们再仔细看一眼汇编代码</p>
<pre><code>//C
int testfunc(){
    int a=0;
}

int testfunc2()
{
    testfunc();
}

</code></pre>
<pre><code>//asm
testfunc:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR -4[rbp], 0
        nop
        pop     rbp
        ret
testfunc2:
        push    rbp
        mov     rbp, rsp
        mov     eax, 0
        call    testfunc
        nop
        pop     rbp
        ret
</code></pre>
<p dir="auto">看汇编代码我们是不是看不哪里压栈了,这时候就要介绍一下call指令的执行过程</p>
<ul>
<li>首先call指令会将PC入栈</li>
<li>然后会有一个jmp跳转到要执行的地址<br />
说起来可能很抽象,下面用一张图来说明他的过程<br />
<img src="/assets/uploads/files/1743075053041-192f617c-e6cb-4f33-9408-d58f907624f4-%E5%9B%BE%E7%89%87-resized.png" alt="192f617c-e6cb-4f33-9408-d58f907624f4-图片.png" class=" img-fluid img-markdown" /><br />
这张图片应该就可以很清晰地描绘call指令都干了些啥了吧!<br />
由此可见,在函数调用的过程中程序的返回地址存在栈栈中,也就是栈上的数据会影响程序的运行过程.试想如果我们修改了栈上特定位置的数值,并修改成特定的数值,那么我们就可以让程序走到意想不到的地方(栈溢出).</li>
</ul>
<h1>32位(x86情况下)</h1>
<h3>先上代码</h3>
<pre><code>int f=0;
int c=0;

int testfunc(){
    int a=0;
    f=1;
    return c;
}

int testfunc2()
{
    testfunc();
}
</code></pre>
<pre><code>f:
        .zero   4
c:
        .zero   4
testfunc:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        call    __x86.get_pc_thunk.ax
        add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
        mov     DWORD PTR -4[ebp], 0
        mov     DWORD PTR f@GOTOFF[eax], 1
        mov     eax, DWORD PTR c@GOTOFF[eax]
        leave
        ret
testfunc2:
        push    ebp
        mov     ebp, esp
        call    __x86.get_pc_thunk.ax
        add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
        call    testfunc
        nop
        pop     ebp
        ret
__x86.get_pc_thunk.ax:
        mov     eax, DWORD PTR [esp]
        ret
</code></pre>
<p dir="auto">我们发现多了一个这个函数 <strong>__x86.get_pc_thunk.ax</strong> 这个是干什么的呢?我们来分析一下<br />
在testfunc2中有这样一条指令</p>
<pre><code>call    __x86.get_pc_thunk.ax
</code></pre>
<p dir="auto">首先call指令会将PC寄存器入栈,然后在  <strong>__x86.get_pc_thunk.ax</strong> 函数中进行了</p>
<pre><code>  eax, DWORD PTR [esp]
</code></pre>
<p dir="auto">这个操作,esp是栈指针指向的是栈顶部也就是刚刚push的数据也就是PC寄存器的数值了,所以说这个函数是获取下一条指令的地址的,原因是因为x86架构下没有获取PC寄存器的指令只能用这种方式获取了.</p>
<h3>PS:为什么要这么做</h3>
<p dir="auto">因为有一个功能叫做PIE(地址随机化)这个可以有效增加栈溢出导致REC风险<br />
接着来看</p>
<pre><code>add     eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
</code></pre>
<p dir="auto">这个 <strong>FLAT:<em>GLOBAL_OFFSET_TABLE</em></strong> 是全局静态变量表所对应add指令的偏移量,这个是在编译时期确定的,所以这个代码的意思是找到全局静态变量表的地址并储存到eax寄存器中,为了方便我在下文分析函数调用的时候会关闭pie得到相对简单的汇编代码</p>
<pre><code>int testfunc(int g){
    g=8;
}

int testfunc2()
{
    testfunc(2);
}

</code></pre>
<pre><code>testfunc:
        push    ebp
        mov     ebp, esp
        mov     DWORD PTR [ebp+8], 8
        nop
        pop     ebp
        ret
testfunc2:
        push    ebp
        mov     ebp, esp
        push    2
        call    testfunc
        add     esp, 4
        nop
        leave
        ret
</code></pre>
<p dir="auto">可以看到在x86下只有栈传参没有寄存器传参,其余的和x64下的是相同的</p>
<h2>PS:如果你想复现的话记得加入-m32 --no-pie这两个编译参数 一个是目标平台是32位的,一个是不使用pie</h2>
]]></description><link>http://forum.d2learn.org/topic/75/c-0x01-c语言是如何进行函数调用的</link><generator>RSS for Node</generator><lastBuildDate>Wed, 12 Aug 2026 01:55:02 GMT</lastBuildDate><atom:link href="http://forum.d2learn.org/topic/75.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 27 Mar 2025 11:43:28 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to C 0x01(C语言是如何进行函数调用的) on Fri, 28 Mar 2025 13:26:04 GMT]]></title><description><![CDATA[<p dir="auto">PC寄存器基本都是有限制的, 一般可以通过间接的方式修改。而且它一般指一个逻辑上的寄存器, 可能每个架构下实现和名字有所不同。总之, 感觉记住它是存储CPU下一条要执行的指令（在机器语言中）的内存地址就可以了</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>架构</th>
<th>PC 名称</th>
<th>可否直接读取</th>
<th>可否直接写入</th>
<th>位数</th>
</tr>
</thead>
<tbody>
<tr>
<td>x86</td>
<td><code>EIP</code></td>
<td>间接</td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title=":x:" alt="❌" /></td>
<td>32</td>
</tr>
<tr>
<td>x86_64</td>
<td><code>RIP</code></td>
<td>间接</td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title=":x:" alt="❌" /></td>
<td>64</td>
</tr>
<tr>
<td>ARM32</td>
<td><code>R15</code> / <code>PC</code></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" /></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" /></td>
<td>32</td>
</tr>
<tr>
<td>ARM64</td>
<td><code>PC</code></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" /></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title=":warning:" alt="⚠" />️ 限制</td>
<td>64</td>
</tr>
<tr>
<td>RISC-V</td>
<td><code>pc</code></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" />（模拟器）</td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--warning" style="height:23px;width:auto;vertical-align:middle" title=":warning:" alt="⚠" />️ 部分支持</td>
<td>32/64</td>
</tr>
<tr>
<td>MIPS</td>
<td><code>PC</code></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title=":x:" alt="❌" /></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/274c.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--x" style="height:23px;width:auto;vertical-align:middle" title=":x:" alt="❌" /></td>
<td>32</td>
</tr>
<tr>
<td>PowerPC</td>
<td><code>NIP</code></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" /></td>
<td><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title=":white_check_mark:" alt="✅" />（特权）</td>
<td>32/64</td>
</tr>
</tbody>
</table>
<hr />
<p dir="auto"><a href="https://en.wikipedia.org/wiki/Program_counter" rel="nofollow ugc">https://en.wikipedia.org/wiki/Program_counter</a></p>
]]></description><link>http://forum.d2learn.org/post/336</link><guid isPermaLink="true">http://forum.d2learn.org/post/336</guid><dc:creator><![CDATA[sunrisepeak]]></dc:creator><pubDate>Fri, 28 Mar 2025 13:26:04 GMT</pubDate></item></channel></rss>