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裡的命令就是採用這樣的方法.