1. 程式人生 > >07 lds檔案與自定義段

07 lds檔案與自定義段

lds檔案用於指定程式連結時的不同段內容的位置安排。linux核心映象裡就是利用lds檔案,把不同的內容劃分成很多不同的段.
uboot裡的命令也就是利用此功能,把所有的命令統一到一個段裡.

arm-linux-gnueabihf-ld –verbose > test.lds //把編譯器預設的連結指令碼輸出到test.lds裡

修改test.lds, 把最前的6行刪除掉, 也要刪除最後一行.
在84行加入自己的段:

  __mysection_start = . ;
  .mysection  :
  {
    *(.mysection);
  }
  .align = 4
; __mysection_end = . ;

// __mysection_start 和 __mysection_end用於記錄段的開始地址與結束地址.
*(.mysection) 表示所有的.o檔案的.mysection段內容集中放起來

在程式碼裡指定變數是分配在.mysection段:

    int num  __attribute__ ((section(".mysection"))) = 1;
    int num2 __attribute__ ((section(".mysection"))) = 2;
    int num3 __attribute__ ((section(".mysection"
))) = 3;

編譯時指定使用test.lds連結指令碼:

arm-linux-gnueabihf-gcc test.c -Ttest.lds -o test

編譯完成後,可以反彙編確認.mysection裡的狀況:

    arm-linux-gnueabihf-objdump -D test 
  檢視到的輸出:
    Disassembly of section .mysection:

    000083d4 <num>:
        83d4:       00000001        andeq   r0, r0, r1

    000083d8 <num2>:
        83
d8: 00000002 andeq r0, r0, r2 000083dc <num3>: 83dc: 00000003 andeq r0, r0, r3

////////////////////////////////////////////////////////////////////
加進一個段後, 可以通過__mysection_start 和__mysection_end算出一個段的大小,及段裡的變數個數.
也可以取出每個段裡變數的值.

在程式碼裡:
__mysection_start 相當於一個變數(型別不重要),它的地址就是段的開始地址
__mysection_end, 它的地址就是段的結束地址
實驗程式碼:
test.c

    #include <stdio.h>

    int num __attribute__ ((section(".mysection"))) = 1;
    int num2 __attribute__ ((section(".mysection"))) = 2;
    int num3 __attribute__ ((section(".mysection"))) = 3;
    int num4 __attribute__ ((section(".mysection"))) = 55; 

    extern int __mysection_start; //這個變數是在連結腳本里宣告的
    extern int __mysection_end;
    int main(void)
    {
        int *p = &__mysection_start;

        for (; p < &__mysection_end; p++)
        {   
        printf("%d\n", *p);
        }   

        return 0;
    }

以後再加變數到.mysection段裡,main函式的程式碼可以不用修改都可以獲取到相應的變數的值
////////////////////////////////////////
實現命令的功能:

test.c

    #include <stdio.h>

    typedef struct {
        char *name;  //命令的名字
        char *help; // 命令的幫助資訊
        void (*func)(void); //命令的功能函式
    }cmd_t;

    #define MySection  __attribute__ ((section(".mysection")))

    #define ADD_CMD(name, help, func) \
        cmd_t __cmd_##name MySection = {#name, help , func}  

    void do_cmd1(void)
    {
        printf("in %s\n", __func__);
    }
    ADD_CMD(cmd1, "help of cmd1", do_cmd1);


    extern cmd_t __mysection_start;
    extern cmd_t __mysection_end;
    int main(void)
    {
        cmd_t *p = &__mysection_start;      

        for (; p < &__mysection_end; p++)
        {
            printf("%s\n", p->name);
            p->func();
            printf("#################\n");
        }
        return 0;
    }

// 再增加命令時,只需實現命令的功能函式後, 呼叫ADD_CMD巨集即可.
// 也可以把每個命令用一個原始檔來實現,最後一起編譯即可。uboot裡的命令就是採用這樣的方法.