GCC - 标签地址返回当前EIP而不是真实标签地址

时间:2016-08-16 21:07:43

标签: c gcc osdev

在尝试编写操作系统时,我需要获取当前函数结束的地址(在结尾之前)以进行任务切换。
具体来说,我的问题是让EIP分配给复制堆栈内新创建的任务(进程)。我已经设法为进程保存/恢复寄存器,但是我需要找到子进程在其EIP中具有的值。

我使用了GCC对C标准的扩展:Labels as ValuesLocal Labels
从文档:您可以使用一元运算符'&&'获取当前函数(或包含函数)中定义的标签的地址。该值的类型为void *。
和: GCC允许您在任何嵌套块范围内声明本地标签。本地标签就像普通标签一样,但您只能在声明它的块中引用它(带有goto语句或取其地址)。

pid_t fork(void)
{
    __label__ fork_end;
    ...
    task->regs.eip = (uintptr_t)&&fork_end;
    ...
    return task->pid;
    fork_end:;
}

GCC确实编译它,只是警告非标准代码 但是当反汇编时,gdb会显示:

    task->regs.eip = (uintptr_t)&&fork_end;
0x00105008 <+87>:   mov    $0x105008,%edx
0x0010500d <+92>:   mov    -0xc(%ebp),%eax
0x00105010 <+95>:   mov    %edx,0x40(%eax)
...
    fork_end:;
    }
0x00105096 <+229>:  leave  
0x00105097 <+230>:  ret 

我希望task->regs.eip = (uintptr_t)&&fork_endl保存0x00105096而不是0x00105008 CFLAGS-O0 -std=gnu99 -fgnu89-inline -DDEBUG -ggdb3 -ffreestanding -fbuiltin(警告相关选项未在此处显示)。

评论__label__ fork_end;不会改变任何内容。

1 个答案:

答案 0 :(得分:1)

似乎编译器完全优化了标签,因为没有代码路径导致它。我已经确认将标签移到return语句之前,并确保在分配和标签之间存在实际代码,这会导致我认为是您期望的行为。这是我放在一起测试的代码:

void *fork(void) {
  __label__ fork_end;
  void *test = &&fork_end;

  test++;

  fork_end:
  return test;
}

基于此,我希望您可以通过稍微重新编写代码路径来确保获得所需的内容,以确保标签点可通过任何代码路径访问。