鏈接 集合

鏈接器的核心是兩個:

符號表

重定位表

工具:

nm file.o

objdump -h a.out  

ld --verbose > defaults.lds 查看默認的鏈接腳本

gcc -fno-builtin    -fno-builtin 用於關閉GCC內部函數功能

gcc -v -nostartfiles -o hello hello.o  不鏈接系統標準啓動文件,而標準庫文件仍然正常使用

gcc -v -nostdlib -o hello hello.o  不鏈接系統標準啓動文件和標準庫文件

ld -static  鏈接默認是動態鏈接 ,靜態鏈接需要加上static指定

程序的入口函數是由鏈接器文件指定或者通過gcc 指定。

ENTRY(hello)

gcc -e

鏈接腳本如下:

ENTRY(hello)   //入口函數不是main()了,是hello

SECTIONS
{
    .text 0x00400000+SIZEOF_HEADERS:    //指定程序的代碼段從0x00400000開始(64位),32位及其爲0x08048400開始
    { 

 //必須加上SIZEOF_HEADERS,否者程序將會變得很大。因爲代碼段佔用了ELF文件的文件頭,導致  ELF文件的相關信息丟失              
        *(.text)

        *(.rodata)
    }
    . = 0x01000000;//當然,不能隨意指定數據的位置,否者容易引起  segment fault ,還是讓程序自己處理
    s1 = .;                //指定程序中參數s1的地址在0x01000000處
    . += 4;                //不指定的話就是有系統分配的地址,可以不管
    s2 = .;               //指定程序中參數s1的地址在0x01000000+4處
    .data :
    {
        *(.data)
    } 
    .bss :
    {
        *(.bss)
    }

    /DISCARD/ :
    {
        *(*)     //放棄所有目標文件中除了前面指定的段外的所有其它段
    }
}//各個段之間存在對齊的問題

 

例子:
void printf(const char* s, int l)
{
    asm  (
        "movl $4, %%eax\n"     // _write系統函數相關
        "movl $1, %%ebx\n"
        "movq %0, %%rcx\n"  //對於64位機器,由於指針是64位的,所以這裏用movq
        "movl %1, %%edx\n"
        "int $0x80     \n"    //通過80H進行interrupt
        :
        : "r"(s), "r"(l)      // printf的參數
        : "eax", "ebx", "ecx", "edx"  // 保留列表
    );
}
void exit(int code)
{
    asm  (
        "movl $1, %%eax\n"   //_exit
        "movl %0, %%ebx\n"
        "int $0x80     \n"
        :
        : "r"(code)        
        : "eax", "ebx"
    );
}

int hello()
{
    printf("D.T.Software\n", 13);
    exit(0);
}

入口程序不是main()了,而是hello()函數。

編譯,彙編時和普通函數是一樣處理,但是當進行連接時,需要用自己編寫的鏈接文件,上面已經給出。

同時,由於程序中用到了printf和exit函數,這個和系統中的printf和exit衝突,如下:

所以,編譯時要加上  -fno-builtin 。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章