---
# System prepended metadata

title: 執行階段程式庫 (CRT)
tags: [C 語言筆記]

---

---
title: 執行階段程式庫 (CRT)
tags: C 語言筆記
---
## 執行階段程式庫 (CRT)
### crt0.o
* crt0.o，又稱為 c0，是連接到 C 語言程式的啟動函式，他們不是函式庫，比較像是內核的組合語言，負責進行程式在進入 main 函式以前的工作，包含初始化程式的 stack，設置中斷請求等等工作，而後面加入了建構函式和解構函式等功能之後被稱為 crt1.o
* crt1.o 裡面包含了進入函式 _start，由 start 呼叫 __libc_start_main 進行初始化，然後呼叫程式中的 main 函式
### CRT 行為
* crt 為 c runtime 的縮寫，描述進入 main 函式之前的初始化和退出main函式的清理工作
* 包含初始化及終止 C/C++ 可執行檔所需的程式碼
* 會提供內部 DLL 進入點函式呼叫
* 會呼叫建構函式和解構函式
* 還有許多功能，如例外處理、偵錯支援、執行時檢查、類型資訊、實現細節與特定擴充函式
### main & C runtime
* 範例: ```int main() { return 1; }```，可以用 ```echo $?``` 來取得回傳值 1 ，其實在程式執行完後會呼叫  exit(result)，而這就是 C runtime (簡稱 crt) 來處理
* int main(int argc, char *argv[])
    * Arguments: expressions passed into a function
    * Parameters: values received by the function
    ![](https://i.imgur.com/0AxO5D8.png)
    * 程式執行時的 envp 也是經由 CRT 傳遞
    * 範例
    ```c=
    #include <stdio.h>
    int main(int argc, char *argv[]) {
        for (char **ptr = (char**) argv; *ptr != NULL; ptr++)
            puts(((char *) *ptr));	
        return 0;
    }
    ```  
    * ```(gdb) x/4s argv[0]```
    * 後 3 項是 envp (environment variables)，在 C run-time 傳遞進來的內容
        ```c=
        0x7fffffffe455:"/home/will/test/ret1"
        0x7fffffffe46a:"SHELL=/bin/bash"
        0x7fffffffe47a:"SESSION_MANAGER=local/will:@/tmp/.ICE-unix/1207,unix/will:/tmp/.ICE-unix/1207"
        0x7fffffffe4c8:"QT_ACCESSIBILITY=1"
        ```
* Linux 系統下程序的入口是 "_start" ，這個函數是 linux 系統庫（Glibc）的一部分，當我們的程式和 Glibc linking 在一起形成最終的可執行文件之後，這個函數就是程序執行初始化的入口函數
* 測試 ``` $gcc test.c -nostdlib ＃ -nostdlib (不使用標準庫) ``` 會出錯 ``` cannot find entry symbol _start ```
* 所以可以結論出
    *  __start 這個符號是程序的起始
    *  main 是被標準庫調用的一個符號
* _start 函式:![](https://i.imgur.com/ArW9sRZ.png)
    * 可以發現在調用 _start 之前，用戶的參數和環境變量就已經被放入 stack 之中了
    *  __libc_start_main 一共有七個參數，其中 
        *  init: 負責 main 開始之前的初始化工作
        *  fini: main 結束之後的收尾工作
        *  rtld_fini(edx): 和動態加載有關的收尾工作
    * main 開始之前的工作:
        * 初始化 stack pointer
        * 初始化 全域 和 靜態 變數，也就是 .data 的內容
        * 將未初始化部分的變數給予初值: 數值型 short，int，long等為 0，bool 為 FALSE，pointer 為 NULL,etc，即 .bss 的內容
        * run global constructors
        * 將 main 函數的參數，argc、argv 等傳遞給 main 函數，然後才真正運行 main 函數
    * main 結束之後執行的函數: ```int atexit(void (*function)(void))```
        * 用來 內存釋放、關閉打開的文件、關閉socket描述符、釋放鎖,etc
        * 使用到 atexit 函式是跟 stack 一樣先進後出的(最先宣告，最晚執行)
### GNU Toolchain
* 編譯的流程還有格式![](https://i.imgur.com/5nADWjO.png)
* 待補 
https://www.bottomupcs.com/compiling.xhtml https://www.bottomupcs.com/libraries.xhtml

###  environ = argv + argc + 1
* 從 argv 之後會接一個 "\0" (NULL)，之後緊接 environ 可以推得
* 從 gdb 觀察:
    * ```(gdb) x/1s argv[0]```: argv 有幾個這邊就會有幾個，所以用 argc 來加
    ``` 0x7fffffffe44b:	"/home/will/test/p_environ" ```
    * ```(gdb) x/1s argv[1]```: "\0"(NULL)，最後的 ＋ 1
    ``` 0x0:	<error: Cannot access memory at address 0x0> ```
    * ```(gdb) x/4s argv[2]```: environ 資料
    ```
    0x7fffffffe465:"SHELL=/bin/bash"
    0x7fffffffe475:"SESSION_MANAGER=local/will:@/tmp/.ICE-unix/1207,unix/will:/tmp/.ICE-unix/1207"
    0x7fffffffe4c3:"QT_ACCESSIBILITY=1"
    0x7fffffffe4d6:"COLORTERM=truecolor"
    ```