除了默认代码和数据用户和内核段之外,我正在尝试使用不同的段进行一些实验。我希望通过使用本地描述符表和 modify_ldt 系统调用来实现这一点。通过系统调用,我在 LDT 中创建了一个新条目,它是一个段描述符,具有我想要“隔离”的全局变量的基地址和 4 个字节的限制。
我尝试通过 C 程序中的内联汇编使用自定义 LDT 条目的段选择器加载数据段寄存器,但是当我尝试访问该变量时,我收到了段错误。
我怀疑我的全局变量的偏移量有问题,当计算地址时,它超出了我的自定义段的限制,因此导致段错误。
有人知道解决这种情况的方法吗?
哦,顺便说一句,这是在 Linux 中的 x86 架构上。这是我第一次在论坛上提出这样的问题,所以如果有任何其他信息可能被证明是有用的,请告诉我。
提前致谢。
编辑:我意识到我可能应该包括源代码:)
struct user_desc* table_entry_ptr = NULL;
/* Allocates memory for a user_desc struct */
table_entry_ptr = (struct user_desc*)malloc(sizeof(struct user_desc));
/* Fills the user_desc struct which represents the segment for mx */
table_entry_ptr->entry_number = 0;
table_entry_ptr->base_addr = ((unsigned long)&mx);
table_entry_ptr->limit = 0x4;
table_entry_ptr->seg_32bit = 0x1;
table_entry_ptr->contents = 0x0;
table_entry_ptr->read_exec_only = 0x0;
table_entry_ptr->limit_in_pages = 0x0;
table_entry_ptr->seg_not_present = 0x0;
table_entry_ptr->useable = 0x1;
/* Writes a user_desc struct to the ldt */
num_bytes = syscall( __NR_modify_ldt,
LDT_WRITE, // 1
table_entry_ptr,
sizeof(struct user_desc)
);
asm("pushl %eax");
asm("movl $0x7, %eax"); /* 0111: 0-Index 1-Using the LDT table 11-RPL of 3 */
asm("movl %eax, %ds");
asm("popl %eax");
mx = 0x407CAFE;
段错误发生在最后一条指令处。
最佳答案
我只能猜测,因为我没有可用的程序集。
我猜你得到段错误的行被编译成类似的东西:
mov ds:[offset mx], 0x407cafe
在哪里offset mx
是 mx
的偏移量在程序的数据段中(如果它是静态变量)或在堆栈中(如果它是自动变量)。无论哪种方式,这个偏移量都是在编译时计算的,无论 DS
是什么,都会使用它。指向。
现在您在这里所做的是创建一个新段,其基地址为 mx
。并且其限制是 0x4
或 0x4fff
(取决于您未指定的 G-bit
)。
如果G-bit
为0,则极限为0x4
,并且由于 mx
极不可能位于地址 0x0
之间和 0x4
原件DS
,当您访问 mx
的偏移量时在新 segmentation 中,您正在跨越限制。
如果G-bit
为1,则极限为0x4fff
.现在只有在原始 mx
出现时才会出现段错误位于0x4fff
之上.
考虑到新段的基数是 mx
, 您可以访问 mx
通过做:
mov ds:[0], 0x407cafe
不过,我不知道如何用 C 语言编写它。
关于c - 使用 LDT(本地描述符表),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1771136/