编译动态链接内核
Compile Dynamically Linked Kernel
我正在尝试在 xv6 内核中实现 KASLR,因此我需要以动态方式 recompile/link 内核(重定位 table)。
由于内核目前是硬编码的,即使我更改内核代码和数据映射,指令仍将引用硬编码的虚拟地址。我需要一种方法来让指令在没有硬编码地址的情况下引用精灵的其他部分。下面是一个例子:
这是当前编译后的示例:
8010018e: 83 ec 0c sub [=10=]xc,%esp
80100191: 68 a7 79 10 80 push [=10=]x801079a7
80100196: e8 b5 01 00 00 call 80100350 <panic>
8010019b: 90 nop
8010019c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi.
如你所见,push指令等指令引用了硬编码的v地址($0x801079a7)。这是因为这个精灵是以静态方式编译的,没有重定位:(readelf printout)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x80100000 0x00100000 0x0b516 0x15668 RWE 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
Section to Segment mapping:
Segment Sections...
00 .text .rodata .stab .stabstr .data .bss
01
There is no dynamic section in this file.
There are no relocations in this file.
我需要有关如何将静态链接的 elf 二进制文件重新编译为带重定位的二进制文件然后能够将内核映射到虚拟内存中任何位置的建议。此外,我必须在引导加载程序中修改什么来解析精灵以通过重定位正确加载它?我是否必须自定义解析内核精灵中包含的 GOT?
以下是编译内核的链接器脚本,主要设置其基本硬编码虚拟地址:0x80100000
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
/* Link the kernel at this address: "." means the current address */
/* Must be equal to KERNLINK */
. = 0x80100000;
.text : AT(0x100000) {
*(.text .stub .text.* .gnu.linkonce.t.*)
}
PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r.*)
}
/* Include debugging information in kernel memory */
.stab : {
PROVIDE(__STAB_BEGIN__ = .);
*(.stab);
PROVIDE(__STAB_END__ = .);
BYTE(0) /* Force the linker to allocate space
for this section */
}
.stabstr : {
PROVIDE(__STABSTR_BEGIN__ = .);
*(.stabstr);
PROVIDE(__STABSTR_END__ = .);
BYTE(0) /* Force the linker to allocate space
for this section */
}
/* Adjust the address for the data segment to the next page */
. = ALIGN(0x1000);
/* Conventionally, Unix linkers provide pseudo-symbols
* etext, edata, and end, at the end of the text, data, and bss.
* For the kernel mapping, we need the address at the beginning
* of the data section, but that's not one of the conventional
* symbols, because the convention started before there was a
* read-only rodata section between text and data. */
PROVIDE(data = .);
/* The data segment */
.data : {
*(.data)
}
PROVIDE(edata = .);
.bss : {
*(.bss)
}
PROVIDE(end = .);
/DISCARD/ : {
*(.eh_frame .note.GNU-stack)
}
}
看来我必须修改 xv6 引导加载程序并重写大部分 os 才能实现动态内核。
我正在尝试在 xv6 内核中实现 KASLR,因此我需要以动态方式 recompile/link 内核(重定位 table)。 由于内核目前是硬编码的,即使我更改内核代码和数据映射,指令仍将引用硬编码的虚拟地址。我需要一种方法来让指令在没有硬编码地址的情况下引用精灵的其他部分。下面是一个例子: 这是当前编译后的示例:
8010018e: 83 ec 0c sub [=10=]xc,%esp
80100191: 68 a7 79 10 80 push [=10=]x801079a7
80100196: e8 b5 01 00 00 call 80100350 <panic>
8010019b: 90 nop
8010019c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi.
如你所见,push指令等指令引用了硬编码的v地址($0x801079a7)。这是因为这个精灵是以静态方式编译的,没有重定位:(readelf printout)
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x001000 0x80100000 0x00100000 0x0b516 0x15668 RWE 0x1000
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
Section to Segment mapping:
Segment Sections...
00 .text .rodata .stab .stabstr .data .bss
01
There is no dynamic section in this file.
There are no relocations in this file.
我需要有关如何将静态链接的 elf 二进制文件重新编译为带重定位的二进制文件然后能够将内核映射到虚拟内存中任何位置的建议。此外,我必须在引导加载程序中修改什么来解析精灵以通过重定位正确加载它?我是否必须自定义解析内核精灵中包含的 GOT?
以下是编译内核的链接器脚本,主要设置其基本硬编码虚拟地址:0x80100000
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS
{
/* Link the kernel at this address: "." means the current address */
/* Must be equal to KERNLINK */
. = 0x80100000;
.text : AT(0x100000) {
*(.text .stub .text.* .gnu.linkonce.t.*)
}
PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r.*)
}
/* Include debugging information in kernel memory */
.stab : {
PROVIDE(__STAB_BEGIN__ = .);
*(.stab);
PROVIDE(__STAB_END__ = .);
BYTE(0) /* Force the linker to allocate space
for this section */
}
.stabstr : {
PROVIDE(__STABSTR_BEGIN__ = .);
*(.stabstr);
PROVIDE(__STABSTR_END__ = .);
BYTE(0) /* Force the linker to allocate space
for this section */
}
/* Adjust the address for the data segment to the next page */
. = ALIGN(0x1000);
/* Conventionally, Unix linkers provide pseudo-symbols
* etext, edata, and end, at the end of the text, data, and bss.
* For the kernel mapping, we need the address at the beginning
* of the data section, but that's not one of the conventional
* symbols, because the convention started before there was a
* read-only rodata section between text and data. */
PROVIDE(data = .);
/* The data segment */
.data : {
*(.data)
}
PROVIDE(edata = .);
.bss : {
*(.bss)
}
PROVIDE(end = .);
/DISCARD/ : {
*(.eh_frame .note.GNU-stack)
}
}
看来我必须修改 xv6 引导加载程序并重写大部分 os 才能实现动态内核。