DATA_SEGMENT_ALIGN

DATA_SEGMENT_ALIGN(maxpagesize, commonpagesize)

等价于:

(ALIGN(maxpagesize) + (. & (maxpagesize - 1)))
或者
(ALIGN(maxpagesize) + ((. + commonpagesize - 1) & (maxpagesize - commonpagesize)))

取决于后面数据段 (位于此表达式结果之后以及 DATA_SEGMENT_END 之间) 是否使用比前 面更小的 commonpagesize 大小的页。如果后面的形式被使用,表示着保存 commonpagesize 字节的运行时内存时,花费的代价最多浪费 commonpagesize 大小的磁 盘空间。

此表达式仅仅能直接使用在 SECTIONS 命令中,不能再任何输出段描述里,且只能在链接 脚本内出现一次。commonpagesize 应当小于或等于 maxpagesize 且应当为目标希望的最 合适的系统页面大小

一个简单例子

SECTIONS
{
    . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE),CONSTANT(COMMONPAGESIZE));
    .data : { *(.data) }
}

e.g. 三个源文件 DemoA.c,DemoB.c 和 DemoC.c,其中 DemoA.c 引用 DemoA.c 和 DemoB.c 里面的函数,使用 GCC 生成独立的目标文件 DemoA.o,DemoB.o 和 DemoC.o。 ld 使用链接脚本 Demo.lds, 并且在 Demo.lds 里面通过使用 DATA_SEGMENT_ALIGN 关 键字对输出段进行对齐:

DemoA.c

extern void print();
extern void exit();

void nomain()
{
    print();
    exit();
}

DemoB.c

char *str = "Hello World\n";

void print()
{
    __asm__ ("movl $13, %%edx\n\t"
             "movl %0, %%ecx\n\t"
             "movl $0, %%ebx\n\t"
             "movl $4, %%eax\n\r"
             "int $0x80\n\t"
             :: "r" (str) : "edx", "ecx", "ebx");
}

DemoC.c

void exit()
{
    __asm__ ("movl $42, %ebx\n\t"
             "movl $1, %eax\n\t"
             "int $0x80\n\t");
}

Demo.lds

ENTRY(nomain)

INPUT(DemoA.o)
INPUT(DemoB.o)
INPUT(DemoC.o)

SECTIONS
{
    . = 0x08048000 + SIZEOF_HEADERS;

    DemoText  : { *(.text) }

    . = 0x08049001;

    . = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE),CONSTANT(COMMONPAGESIZE));

    DemoData : { *(.data) }

    DemoRD : { *(.rodata) }

    .eh_frame : { *(.eh_frame) }

    /DISCARD/ : { *(.comment) }
}

使用如下命令进行编译和链接:

gcc DemoA.c -c
gcc DemoB.c -c
gcc DemoC.c -c -fno-builtin
ld -static -T Demo.lds -o a.out
objdump -xSsdh a.out

LD

通过运行的数据可知,输出 DemoData 的 VMA 地址就是 0x0804a004,而不是 0x08049001。


附录

BiscuitOS Home

BiscuitOS Driver

BiscuitOS Kernel Build

Linux Kernel

Bootlin: Elixir Cross Referencer

赞赏一下吧 🙂

MMU