[英]Why can't we define the array size by a variable when we write C++ code in vs code?
[英]When we compile a source code that contains a 'main' without linking, why can't we run it?
我正在學習編譯過程,我知道鏈接主要用於鏈接包含'main'函數的二進制文件和包含在我們的主函數中使用的其他輔助函數的其他二進制文件。
但是,當我嘗試使用代碼運行目標文件時:
int main() {
return 0;
}
在Ubuntu上使用gcc中的-c命令編譯,我嘗試運行它並得到錯誤:
“bash:./ source.o:無法執行二進制文件:exec格式錯誤”
閱讀Levine的連接器和裝載器 。
了解ELF 。
嘗試使用gcc -v
編譯(你會看到使用的實際程序是什么: cc1
將C代碼編譯成某個匯編程序,然后as
其匯編到某個目標文件中,將ld
和collect2
到鏈接 )。 還可以使用gcc -S -fverbose-asm -O
查看生成的匯編程序文件。 請注意, gcc
知道(並特別編譯) main
函數。 並且可執行文件的起點由一些crt0等提供(它不是 main
但是一些_start
例程在匯編程序中編碼,它調用你的main
....)。
對象文件與可執行文件不同 。 可執行文件包含諸如crt0和C標准庫之類的東西,或者某種方式將它作為共享對象 動態鏈接 (並且需要將source.o
-compiled從source.c
的空main
鏈接到可執行文件中,因為這樣) )。
在Linux上,使用objdump(1)和readelf(1) (在一些現有的二進制文件上,以及在你的source.o
目標文件中)
另請參閱elf(5) , execve(2) , ld-linux(8) , Linux匯編howto , syscalls(2) , 高級Linux編程 , 操作系統:三個簡單的部分 ,以及(了解libc.so
)Drepper的如何寫共享圖書館 , 龍書 ......
(你需要閱讀整本書才能理解細節;我給了一些參考資料)
你沒有引導程序。 你是在這個雞和蛋的問題。
代碼(用於該函數)就在那里,但有一些假設,首先你需要一個堆棧。 例如,根據架構,您的返回地址可能位於該堆棧上。 返回值可以在該堆棧上。 C語言本身並不直接在語言中提供,因此總是至少需要一些程序集或一些其他語言才能“引導”你的函數。 例如在ARM中用於gnu:
bs.s
.globl _start
_start:
mov sp,#0x8000
bl main
b .
so.c
int main ( void )
{
return(0);
}
對於ARM,函數完成后,鏈接器不需要修改指令。 但是沒有定義地址空間,無論是指定還是反匯編程序都假定零作為此對象的地址,但它是一個對象而不是可加載的二進制文件。
00000000 <main>:
0: e3a00000 mov r0, #0
4: e12fff1e bx lr
現在,如果我們添加引導程序並鏈接到某個地址,我們將獲得一個真實的,可執行的程序
00008000 <_start>:
8000: e3a0d902 mov sp, #32768 ; 0x8000
8004: eb000000 bl 800c <main>
8008: eafffffe b 8008 <_start+0x8>
0000800c <main>:
800c: e3a00000 mov r0, #0
8010: e12fff1e bx lr
它並不意味着無法創建操作系統,也無法使用編譯器對象輸出以這種方式加載函數。 但這就是單詞鏈,工具鏈的原因。 編譯器使用匯編語言,匯編程序匯編匯編語言,結合其他必要的對象(引導程序加編譯器庫和C庫等),鏈接器為所有內容定義地址空間,並根據需要修改代碼/數據以解析外部。 獲得最終結果的序列或事件鏈。
即使像exit
這樣的最基本的命令也不是直接在語言中,需要鏈接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.