链接脚本(link script)语法

链接脚本(link script)语法

语法

1. 定义一个section,如下是define一个.init.data section

*(.init.rodata.* .init.bss)最前面的*是通配符,表示所有.o文件的(.init.rodata.*、.init.bss section)

    .init.data : {
        INIT_DATA
        INIT_SETUP(16)
        INIT_CALLS
        CON_INITCALL
        SECURITY_INITCALL
        INIT_RAM_FS
        *(.init.rodata.* .init.bss)    /* from the EFI stub */
    }

 

2. define变量

点表示当前地址,这个变量在c文件里extern后就可以使用了,如下例子

_text_start、_text_end保存了所在位置的链接地址,在这两个链接地址中间就是.text段的大小,编译完成后可以在System.map里查看这两个变量的地址

    .text :
    {
        _text_start = .;
        *(.__image_copy_start)
        CPUDIR/start.o (.text*)
    }

    /* This needs to come before *(.text*) */
    .efi_runtime : {
                __efi_runtime_start = .;
        *(.text.efi_runtime*)
        *(.rodata.efi_runtime*)
        *(.data.efi_runtime*)
                __efi_runtime_stop = .;
    }

    .text_rest :
    {
        *(.text*)
    }
    _text_end = .;

 

在header里extern,然后include此header就可以在c source文件里引用它们了,_text_end - _text_start的结果即为它俩中间的.text段的size

extern char _text_start[], _text_end[];

 

 

INIT_CALLS

arch/arm64/kernel/vmlinux.lds.S

    __inittext_end = .;
    __initdata_begin = .;

    .init.data : {
        INIT_DATA
        INIT_SETUP(16)
        INIT_CALLS
        CON_INITCALL
        SECURITY_INITCALL
        INIT_RAM_FS
        *(.init.rodata.* .init.bss)    /* from the EFI stub */
    }
    .exit.data : {
        ARM_EXIT_KEEP(EXIT_DATA)
    }

    PERCPU_SECTION(L1_CACHE_BYTES)

    .rela.dyn : ALIGN(8) {
        *(.rela .rela*)
    }

    rela_offset    = __ABSOLUTE(ADDR(.rela.dyn) - KIMAGE_VADDR);
    __rela_size    = SIZEOF(.rela.dyn);

    . = ALIGN(SEGMENT_ALIGN);
    __initdata_end = .;
    __init_end = .;

 

include/asm-generic/vmlinux.lds.h

#define INIT_CALLS_LEVEL(level)                        \
        __initcall##level##_start = .;                \
        KEEP(*(.initcall##level##.init))            \
        KEEP(*(.initcall##level##s.init))            \

#define INIT_CALLS                            \
        __initcall_start = .;                    \
        KEEP(*(.initcallearly.init))                \
        INIT_CALLS_LEVEL(0)                    \
        INIT_CALLS_LEVEL(1)                    \
        INIT_CALLS_LEVEL(2)                    \
        INIT_CALLS_LEVEL(3)                    \
        INIT_CALLS_LEVEL(4)                    \
        INIT_CALLS_LEVEL(5)                    \
        INIT_CALLS_LEVEL(rootfs)                \
        INIT_CALLS_LEVEL(6)                    \
        INIT_CALLS_LEVEL(7)                    \
        __initcall_end = .;

 

从上面的code可以看出各个level的initcall是连续存放的,0在最前,7在最后,这个顺序会决定它们在开机过程时的执行先后,数字越小的越先执行,数字越大越后执行。

而且这些initcall都是存放在.init.data section的。

上述macro展开可以得知各个等级的initcall有如下这些,这些initcall所在的区间为[__initcall_start, __initcall_end]

.initcall0.init
.initcall1.init
.initcall2.init
.initcall3.init
.initcall4.init
.initcall5.init
.initcallrootfs.init
.initcall6.init
.initcall7.init

.initcall0s.init
.initcall1s.init
.initcall2s.init
.initcall3s.init
.initcall4s.init
.initcall5s.init
.initcallrootfss.init
.initcall6s.init
.initcall7s.init

 

posted @ 2021-11-07 20:45  aspirs  阅读(993)  评论(0编辑  收藏  举报