中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 牛人業(yè)話 > C語言的那些小秘密之函數(shù)的調(diào)用關(guān)系

        C語言的那些小秘密之函數(shù)的調(diào)用關(guān)系

        作者: 時(shí)間:2015-03-09 來源:網(wǎng)絡(luò) 收藏

          參數(shù)的壓棧是從右向左的,即先壓最后一個(gè)參數(shù),在壓倒數(shù)第二個(gè),以此類推,最后才壓入第一個(gè)參數(shù)。為了加深大家的印象,下面我給出一個(gè)測(cè)試代碼:

        本文引用地址:http://www.antipu.com.cn/article/270700.htm

          #include

          void turn(int x, int y, int z)

          {

          printf("x = %d at [%X]n", x, &x);

          printf("y = %d at [%X]n", y, &y);

          printf("z = %d at [%X]n", z, &z);

          }

          int main(int argc, char *argv[])

          {

          turn(1, 2, 3);

          return 0;

          }

          運(yùn)行結(jié)果為:

          

         

          比較打印出來的地址可以看出參數(shù)z的地址是最大的,x的地址最小。

          參數(shù)的壓棧工作完成之后,接下來就依次是EIP、EBP、臨時(shí)變量的壓棧操作了。最后壓入的是被調(diào)用本身,并為它分配臨時(shí)的變量空間,而對(duì)于不同版本的gcc的處理方式各有不同,老版本的gcc第一個(gè)臨時(shí)變量放在最高的地址,第二個(gè)其次,依次順序分布,新版本的gcc則與之相反。

          實(shí)現(xiàn)backtrace()的調(diào)用關(guān)系,其步驟如下:

          1.獲取當(dāng)前函數(shù)的EBP;

          2.通過EBP獲得調(diào)用者得EIP;

          3.通過EBP獲得上一級(jí)的EBP;

          4.重復(fù)這個(gè)過程,知道結(jié)束。

          自己實(shí)現(xiàn)的backtrace()函數(shù),代碼如下:

          #include

          #define MAX_LEVEL 4

          #define OFFSET 4

          int backtrace(void** buffer, int size)

          {

          int n = 0x23f;

          int* p = &n;

          int i = 0;

          int ebp = p[1 + OFFSET];

          int eip = p[2 + OFFSET];

          for(i = 0; i < size; i++)

          {

          buffer[i] = (void*)eip;

          p = (int*)ebp;

          ebp = p[0];

          eip = p[1];

          }

          return size;

          }

          static void call2()

          {

          int i = 0;

          void* buffer[MAX_LEVEL] = {0};

          int size=backtrace(buffer, MAX_LEVEL);

          for(i = 0; i < size; i++)

          {

          printf("called by %pn", buffer[i]);

          }

          return;

          }

          static void call1()

          {

          call2();

          return;

          }

          static void call()

          {

          call1();

          return;

          }

          int main(int argc, char* argv[])

          {

          call();

          return 0;

          }

          運(yùn)行結(jié)果如下:

          root@ubuntu:/home/shiyan# gcc -g bac.c -o tt

          root@ubuntu:/home/shiyan# ./tt

          called by 0x8048491

          called by 0x80484ce

          called by 0x80484db

          called by 0x80484e8

          轉(zhuǎn)換為源代碼位置:root@ubuntu:/home/shiyan# ./tt |awk '{print "addr2line "$3" -e tt"}'>t.sh;. t.sh;rm -f t.sh

          root@ubuntu:/home/shiyan# ./tt |awk '{print "addr2line "$3" -e tt"}'>t.sh;. t.sh;rm -f t.sh

          /home/shiyan/bac.c:32

          /home/shiyan/bac.c:47

          /home/shiyan/bac.c:54

          /home/shiyan/bac.c:60

          在此重點(diǎn)介紹下backtrace()函數(shù)的實(shí)現(xiàn)原理。

          通過 int* p = &n;來獲取第一個(gè)臨時(shí)變量的位置,因?yàn)槲沂褂玫氖切掳姹镜膅cc,有5個(gè)臨時(shí)變量,所以EIP的值存放在p[6]中,EBP的的值存放在p[5],通過 buffer[i] = (void*)eip;可以把eip的強(qiáng)制轉(zhuǎn)換為可以指向任意類型的指針, 接下來通過 p = (int*)ebp;來獲得上一個(gè)函數(shù)的ebp,獲得ebp之后由ebp和eip的位置關(guān)系可以得到eip,由于ebp指向的單元存儲(chǔ)的是上一個(gè)函數(shù)的ebp,所以用一個(gè)簡(jiǎn)單的for循環(huán)就能實(shí)現(xiàn)了。

          另外在頭文件"execinfo.h"中除了聲明backtrace()函數(shù)外,還有如下兩個(gè)函數(shù)也用于獲取當(dāng)前線程的函數(shù)調(diào)用堆棧。

          char ** backtrace_symbols (void *const *buffer, int size)

          backtrace_symbols將從backtrace函數(shù)獲取的信息轉(zhuǎn)化為一個(gè)字符串?dāng)?shù)組. 參數(shù)buffer應(yīng)該是從backtrace函數(shù)獲取的數(shù)組指針,size是該數(shù)組中的元素個(gè)數(shù)(backtrace的返回值)

          函數(shù)返回值是一個(gè)指向字符串?dāng)?shù)組的指針,它的大小同buffer相同.每個(gè)字符串包含了一個(gè)相對(duì)于buffer中對(duì)應(yīng)元素的可打印信息.它包括函數(shù)名,函數(shù)的偏移地址,和實(shí)際的返回地址

          現(xiàn)在,只有使用ELF二進(jìn)制格式的程序和苦衷才能獲取函數(shù)名稱和偏移地址.在其他系統(tǒng),只有16進(jìn)制的返回地址能被獲取.另外,你可能需要傳遞相應(yīng)的標(biāo)志給鏈接器,以能支持函數(shù)名功能(比如,在使用GNU ld的系統(tǒng)中,你需要傳遞(-rdynamic)),該函數(shù)的返回值是通過malloc函數(shù)申請(qǐng)的空間,因此調(diào)用這必須使用free函數(shù)來釋放指針。

          注意:如果不能為字符串獲取足夠的空間函數(shù)的返回值將會(huì)為NULL。

          Function:void backtrace_symbols_fd (void *const *buffer, int size, int fd)

          backtrace_symbols_fd與backtrace_symbols 函數(shù)具有相同的功能,不同的是它不會(huì)給調(diào)用者返回字符串?dāng)?shù)組,而是將結(jié)果寫入文件描述符為fd的文件中,每個(gè)函數(shù)對(duì)應(yīng)一行.它不需要調(diào)用malloc函數(shù),因此適用于有可能調(diào)用該函數(shù)會(huì)失敗的情況。

          還是那句話,以上內(nèi)容難免有誤,如有錯(cuò)誤,請(qǐng)糾正。

        c語言相關(guān)文章:c語言教程



        上一頁 1 2 下一頁

        關(guān)鍵詞: C語言 函數(shù)

        評(píng)論


        相關(guān)推薦

        技術(shù)專區(qū)

        關(guān)閉