<?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 0x00(C语言是如何进行函数调用的)]]></title><description><![CDATA[<h1>C语言是如何进行函数调用的，换句话说C语言进行函数调用时都发生了些什么</h1>
<h3>先写一段简单的C语言程序(不传参)</h3>
<pre><code>#include &lt;iostream&gt;
int test(){
    int a=0;
    return 0;
}
int main()
{
    test();
}
</code></pre>
<p dir="auto">这里我们简单的调用了一个函数test,我们对其进行反汇编，查看汇编代码,我用的编译器是gcc,使用clang会有不同的结果但都是大同小异</p>
<pre><code>test():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR -4[rbp], 0
        mov     eax, 0
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        call    test()
        mov     eax, 0
        pop     rbp
        ret
</code></pre>
<p dir="auto">首先我们知道，rbp是栈的基指针，rsp是栈的顶部的指针。人话说rsp、rbp这两个指针夹着栈。<br />
在调用的时候执行了一条指令</p>
<pre><code>push rbp
</code></pre>
<p dir="auto">也就是把rbp入栈，就是先要把rbp的值暂时存起来，以后要用到。接着是</p>
<pre><code>mov rbp, rsp
</code></pre>
<p dir="auto">将rsp赋值给rbp,也就是将rbp指针移动至rsp。这样做是为了给test函数开辟一个属于他自己的栈。<br />
我会搞一个动画、可能会直观一些</p>
<p dir="auto">首先说明32位、64位下的函数传参有一些不同</p>
<h3>传参的情况下(64位)</h3>
<pre><code>int test(int b,int c,int d,int e,int f, int g,int h,int i){
    b=1;
    c=2;
    d=3;
    e=4;
    f=5;
    g=6;
    h=7;
    i=8;
}
int main()
{
    int b=0;   
    test(1,2,3,4,5,6,7,8);
}
</code></pre>
<p dir="auto">汇编如下</p>
<pre><code>test:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR -4[rbp], edi
        mov     DWORD PTR -8[rbp], esi
        mov     DWORD PTR -12[rbp], edx
        mov     DWORD PTR -16[rbp], ecx
        mov     DWORD PTR -20[rbp], r8d
        mov     DWORD PTR -24[rbp], r9d
        mov     DWORD PTR -4[rbp], 1
        mov     DWORD PTR -8[rbp], 2
        mov     DWORD PTR -12[rbp], 3
        mov     DWORD PTR -16[rbp], 4
        mov     DWORD PTR -20[rbp], 5
        mov     DWORD PTR -24[rbp], 6
        mov     DWORD PTR 16[rbp], 7
        mov     DWORD PTR 24[rbp], 8
        nop
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR -4[rbp], 0
        push    8
        push    7
        mov     r9d, 6
        mov     r8d, 5
        mov     ecx, 4
        mov     edx, 3
        mov     esi, 2
        mov     edi, 1
        call    test
        add     rsp, 16
        mov     eax, 0
        leave
        ret
</code></pre>
<p dir="auto">可以看到传参的顺序是从右到左的，至于为什么要这样传参是因为栈的性质，先进后出第一个参数最后入栈，那么取出的时候是第一个取出的，这样设计的话就可以支持可变参数了。<br />
然后在看这一段</p>
<pre><code>        mov     r9d, 6
        mov     r8d, 5
        mov     ecx, 4
        mov     edx, 3
        mov     esi, 2
        mov     edi, 1
</code></pre>
<p dir="auto">这是主调函数(就是调用其他函数的那个函数)把参数放到了寄存器里，是这样的，在64位C程序中函数调用优先使用寄存器(快)64位CPU的寄存器很多的可以看到顺序</p>
<ul>
<li>edi(rdi)</li>
<li>esi(rsi)</li>
<li>edx(rdx)</li>
<li>ecx(rcx)</li>
<li>r8d</li>
<li>r9d<br />
如果参数更多的话，使用栈传参。<br />
但是即使他用了寄存器传参他也一定会放到栈里的，这个操作是在test函数里实现的</li>
</ul>
<pre><code>test:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR -4[rbp], edi
        mov     DWORD PTR -8[rbp], esi
        mov     DWORD PTR -12[rbp], edx
        mov     DWORD PTR -16[rbp], ecx
        mov     DWORD PTR -20[rbp], r8d
        mov     DWORD PTR -24[rbp], r9d
</code></pre>
<p dir="auto">这一段。到这里你一定会感到疑惑<img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f914.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--thinking_face" style="height:23px;width:auto;vertical-align:middle" title=":thinking_face:" alt="🤔" />，为什么</p>
<pre><code>        mov     DWORD PTR 16[rbp], 7
        mov     DWORD PTR 24[rbp], 8
</code></pre>
<p dir="auto">这两行和其他两行不一样的说<br />
都是int 前面的占4个字节，这两个占8个字节，并且前面的是减，后面的是加。<br />
然后还是从16开始的，好奇怪!</p>
<h2><strong>思考</strong></h2>
<ul>
<li>rbp寄存器的大小.</li>
<li>pc寄存器大小.</li>
<li>再想想为什么函数调用后能回到调用它的地方.</li>
</ul>
<p dir="auto">如果想通了这两件事，问题就迎刃而解了，如果没想明白，下一篇文章将会解答<br />
至于为什么下面是占据8个字节全因为push指令，他一次会压入8个字节(64位cpu)，所以就要配合人家<br />
然后为什么上面是4个字节，因为我这个编译器下int占据4个字节。有可能其他编译器64位程序中int 占据8个字节</p>
<h3>传参的情况下(32位)</h3>
<p dir="auto">未完待续。。。</p>
]]></description><link>http://forum.d2learn.org/topic/52/c-0x00-c语言是如何进行函数调用的</link><generator>RSS for Node</generator><lastBuildDate>Wed, 16 Sep 2026 12:34:57 GMT</lastBuildDate><atom:link href="http://forum.d2learn.org/topic/52.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 14 Dec 2024 23:35:41 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to C 0x00(C语言是如何进行函数调用的) on Mon, 31 Mar 2025 09:01:19 GMT]]></title><description><![CDATA[<h1>太</h1>
<h1>强</h1>
<h1>了</h1>
<h1><img src="http://forum.d2learn.org/assets/plugins/nodebb-plugin-emoji/emoji/android/1f44d.png?v=c6uec18e3vu" class="not-responsive emoji emoji-android emoji--+1" style="height:23px;width:auto;vertical-align:middle" title=":+1:" alt="👍" /></h1>
]]></description><link>http://forum.d2learn.org/post/338</link><guid isPermaLink="true">http://forum.d2learn.org/post/338</guid><dc:creator><![CDATA[kxb520]]></dc:creator><pubDate>Mon, 31 Mar 2025 09:01:19 GMT</pubDate></item><item><title><![CDATA[Reply to C 0x00(C语言是如何进行函数调用的) on Wed, 18 Dec 2024 03:40:00 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="http://forum.d2learn.org/uid/1">@sunrisepeak</a> 有道理，完善了</p>
]]></description><link>http://forum.d2learn.org/post/201</link><guid isPermaLink="true">http://forum.d2learn.org/post/201</guid><dc:creator><![CDATA[妈耶厥了]]></dc:creator><pubDate>Wed, 18 Dec 2024 03:40:00 GMT</pubDate></item><item><title><![CDATA[Reply to C 0x00(C语言是如何进行函数调用的) on Sun, 15 Dec 2024 17:32:09 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="http://forum.d2learn.org/uid/7">@妈耶厥了</a> 可以再加一个参数, 显示函数传参是怎么完成的</p>
]]></description><link>http://forum.d2learn.org/post/200</link><guid isPermaLink="true">http://forum.d2learn.org/post/200</guid><dc:creator><![CDATA[sunrisepeak]]></dc:creator><pubDate>Sun, 15 Dec 2024 17:32:09 GMT</pubDate></item></channel></rss>