2012-07-30 70 views
0

我目前正在編譯一個購買的數據堆棧在C中。我使用自己的工具來編譯它,在後臺gcc中使用。我可以將標誌和參數傳遞給gcc,因爲我認爲合適。我想知道,從哪個文件中使用main()。也就是說,在項目中,哪個文件是起點。有沒有辦法告訴gcc生成一個文件列表,或類似的,因爲我不知道從哪個文件是main()被採取?謝謝。找到開始點,int main()

+0

應該只有一個包含'main'函數的文件,否則你會得到一個鏈接器錯誤。除非你告訴我們它是什麼工具,否則你的工具放在了我們無法知道的地方。 – 2012-07-30 10:40:02

+0

順便說一句,這是一個非常糟糕的主意,試圖解決諸如此類的無證細節。 – 2012-07-30 10:40:39

+0

爲什麼不是:grep -rni「main」。 ? – JohnTortugo 2013-06-22 21:56:04

回答

0

您編譯調試符號的項目,可執行啓動gdb,寫list main,其次是「break」或直接break main

+2

'list main'甚至不顯示OP實際需要的文件名。 – 2012-07-30 11:07:12

+0

謝謝你的回答。事實上,這並沒有顯示確切的文件,但顯示了使用的main的第一行,我可以對整個源代碼進行正常的文本搜索並找到插入位置。再次感謝您的答覆。 – 2012-07-30 11:25:50

+0

如果你想查看行號和文件,你可以寫'break main',或者你在'list main'之後'break',等等。你不需要grep。 – alinsoar 2012-07-30 11:40:52

1

從哪裏main()被稱爲是實現依賴 - 使用GCC,它很可能是在被稱爲crt0.ocrt1.o從它叫做/ usr/lib目錄存根對象文件。 (該文件包含操作系統相關的符號,當您的應用程序加載到內存中時,該符號將由內核自動調用。在Linux和Mac OS X上,這稱爲start)。

3

您可以反彙編最終的可執行文件以找到起點。雖然你還沒有提供任何額外的信息來幫助你更多。我正在使用示例代碼來演示此過程。

#include <stdio.h> 

    int main() { 
      printf("hello world\n"); 
      return 0; 
    } 

現在對象main.o有以下這

[[email protected] sf]# gcc -c main.c 
[[email protected] sf]# nm main.o 
0000000000000000 T main 
       U puts 

你可以看到主未初始化。因爲它會在連接階段改變。現在鏈接後:

$gcc main.o 
$nm a.out 
       U [email protected]@GLIBC_2.2.5 
0000000000600874 A _edata 
0000000000600888 A _end 
00000000004005b8 T _fini 
0000000000400390 T _init 
00000000004003e0 T _start 
000000000040040c t call_gmon_start 
0000000000600878 b completed.6347 
0000000000600870 W data_start 
0000000000600880 b dtor_idx.6349 
00000000004004a0 t frame_dummy 
00000000004004c4 T main 

您會看到main有一個地址。但它仍然不是最終的。因爲這個main將被C運行時動態調用。你可以看到誰做的U [email protected]@GLIBC_2.2.5部分:

[[email protected] sf]# ldd a.out 
    linux-vdso.so.1 => (0x00007fff61de1000) /* the linux system call interface */ 
    libc.so.6 => /lib64/libc.so.6 (0x0000003c96000000) /* libc runime , this will invoke your main*/ 
    /lib64/ld-linux-x86-64.so.2 (0x0000003c95c00000) /* dynamic loader */ 

現在,您可以驗證這一點通過查看拆解:

00000000004003e0 <_start>: 
.......... 
4003fd: 48 c7 c7 c4 04 40 00 mov rdi,0x4004c4 /* address of start of main */ 
400404: e8 bf ff ff ff   call 4003c8 <[email protected]> /* this will set up the environment for main, like pushing argc and argv to stack */ 
........... 

如果你不與你的來源,那麼你可以搜索請參閱libc_start_mainmainstart以查看您的可執行文件如何初始化並啓動main

現在,所有這些都是在鏈接完成時使用默認鏈接器腳本完成的。許多大型項目將使用自己的鏈接器腳本。如果您的項目具有自定義鏈接器腳本,則根據所使用的鏈接器腳本,查找起始點將會有所不同。有些項目不使用glibc's運行時。在這種情況下,它仍然有可能通過黑客攻擊目標文件,庫檔案等來找到起點。

如果您的二進制文件是符號的stripped,那麼您必須實際依賴您的彙編程序技能來查找它的起始位置。 (商業軟件供應商的一種慣例)。我認爲你沒有源代碼,那就是堆棧只與一些庫和一些頭文件定義一起分發。

但是,如果你有與你的來源,那麼它只是太瑣碎。只需grep即可通過它。有些答案已經指出了。

0

您可以使用objdump -t來列出目標文件中的符號。因此,假如你是在Linux上,並假設目標文件仍然在周圍的地方,你可以這樣做:

find -name '*.o' -print0 \ 
| xargs -0 objdump -t \ 
| awk '/\.o:/{f=$1} /\.text\.main/{print f, $6}' 

這將打印對象的文件列表和它們所包含的main引用。通常應該有一個從目標文件到源文件的簡單映射。如果有多個包含該符號的目標文件,則取決於實際鏈接到正在查看的二進制文件中的哪一個,因爲每個可執行二進制文件不能超過一個main(除了某些真正具有異國情調的黑色魔法)。

在應用程序鏈接並且調試符號被剝離後,通常沒有指示特定函數來自哪個源文件。這個例外是包括函數名稱作爲字符串文字的文件,例如,使用宏__FILE__。在剝離調試符號之前,您可以使用調試器來獲取該信息。如果包含調試符號,那就是。