为什么使用此链接器脚本在 bss 外部定义零初始化全局变量?
Why are zero-initialized globals defined outside of bss using this linker script?
我有以下两个变量,KMEM_END
和 MEM_TOP
:
extern char _kernel_mem_end[];
extern char _physical_mem_end[];
uint64_t KMEM_END;
uint64_t MEM_TOP;
void kmem_init()
{
kprintf("\nkmem_end: %p\n", (uint64_t) _kernel_mem_end);
kprintf("phys_top: %p\n", (uint64_t) _physical_mem_end);
kprintf("&KMEM_END: %p\n", &KMEM_END);
kprintf("&MEM_TOP: %p\n", &MEM_TOP);
// ...
}
我有链接描述文件提供的_kernel_mem_end
和_physical_mem_end
,这里:
OUTPUT_ARCH("riscv");
ENTRY(start);
MEMORY {
/* The -kernel QEMU option copies the image to that specific address. */
ram (wxa) : ORIGIN = 0x80000000, LENGTH = 128M
}
SECTIONS {
/* Starts at the address 0x80000000. */
.text : ALIGN(4K) {
PROVIDE(_text_start = .);
*(.init)
*(.text .text.*)
. = ALIGN(4K);
PROVIDE(_text_end = .);
} >ram
.data : ALIGN(4K) {
PROVIDE(_data_start = .);
*(.data .data.*)
. = ALIGN(16);
*(.sdata .sdata.*)
. = ALIGN(4K);
PROVIDE(_data_end = .);
} >ram
.rodata : ALIGN(4K) {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
. = ALIGN(16);
*(.srodata .srodata.*)
. = ALIGN(4K);
PROVIDE(_rodata_end = .);
} >ram
.bss : ALIGN(4K) {
PROVIDE(_bss_start = .);
*(.bss .bss.*)
. = ALIGN(4K);
PROVIDE(_stack_start = .);
. += 0x10000;
PROVIDE(_stack_end = .);
PROVIDE(_bss_end = .);
} >ram
. = ALIGN(4K);
PROVIDE(_kernel_mem_end = .);
PROVIDE(_physical_mem_end = ORIGIN(ram) + LENGTH(ram));
}
由于变量是全局变量且未初始化(默认初始化为零),我希望它们位于 BSS 部分。然而kmem_init
的输出结果如下:
kmem_end: 80015000
phys_top: 88000000
&KMEM_END: 80015008
&MEM_TOP: 80015000
这意味着两个变量位于 _kernel_mem_end
和 _physical_mem_end
之间,这根本不是“标准”部分(最重要的是,不是 bss。)
我通过将它们初始化为非零值来让它们驻留在数据部分中,这对我的目的来说很好。我可以将它们初始化为任何值,因为我将覆盖初始值。但是,我想知道为什么会这样?
在调用ld
时使用--orphan-handling=error
,我发现目标文件中存在.sbss
,但从未包含在统一的最终可执行文件中。
所以使用 *(.bss .bss.* .sbss .sbss.*)
而不是 *(.bss .bss.*)
解决了这个问题。
我有以下两个变量,KMEM_END
和 MEM_TOP
:
extern char _kernel_mem_end[];
extern char _physical_mem_end[];
uint64_t KMEM_END;
uint64_t MEM_TOP;
void kmem_init()
{
kprintf("\nkmem_end: %p\n", (uint64_t) _kernel_mem_end);
kprintf("phys_top: %p\n", (uint64_t) _physical_mem_end);
kprintf("&KMEM_END: %p\n", &KMEM_END);
kprintf("&MEM_TOP: %p\n", &MEM_TOP);
// ...
}
我有链接描述文件提供的_kernel_mem_end
和_physical_mem_end
,这里:
OUTPUT_ARCH("riscv");
ENTRY(start);
MEMORY {
/* The -kernel QEMU option copies the image to that specific address. */
ram (wxa) : ORIGIN = 0x80000000, LENGTH = 128M
}
SECTIONS {
/* Starts at the address 0x80000000. */
.text : ALIGN(4K) {
PROVIDE(_text_start = .);
*(.init)
*(.text .text.*)
. = ALIGN(4K);
PROVIDE(_text_end = .);
} >ram
.data : ALIGN(4K) {
PROVIDE(_data_start = .);
*(.data .data.*)
. = ALIGN(16);
*(.sdata .sdata.*)
. = ALIGN(4K);
PROVIDE(_data_end = .);
} >ram
.rodata : ALIGN(4K) {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
. = ALIGN(16);
*(.srodata .srodata.*)
. = ALIGN(4K);
PROVIDE(_rodata_end = .);
} >ram
.bss : ALIGN(4K) {
PROVIDE(_bss_start = .);
*(.bss .bss.*)
. = ALIGN(4K);
PROVIDE(_stack_start = .);
. += 0x10000;
PROVIDE(_stack_end = .);
PROVIDE(_bss_end = .);
} >ram
. = ALIGN(4K);
PROVIDE(_kernel_mem_end = .);
PROVIDE(_physical_mem_end = ORIGIN(ram) + LENGTH(ram));
}
由于变量是全局变量且未初始化(默认初始化为零),我希望它们位于 BSS 部分。然而kmem_init
的输出结果如下:
kmem_end: 80015000
phys_top: 88000000
&KMEM_END: 80015008
&MEM_TOP: 80015000
这意味着两个变量位于 _kernel_mem_end
和 _physical_mem_end
之间,这根本不是“标准”部分(最重要的是,不是 bss。)
我通过将它们初始化为非零值来让它们驻留在数据部分中,这对我的目的来说很好。我可以将它们初始化为任何值,因为我将覆盖初始值。但是,我想知道为什么会这样?
在调用ld
时使用--orphan-handling=error
,我发现目标文件中存在.sbss
,但从未包含在统一的最终可执行文件中。
所以使用 *(.bss .bss.* .sbss .sbss.*)
而不是 *(.bss .bss.*)
解决了这个问题。