标签地址返回当前的EIP而不是实际的标签地址

  • 本文关键字:标签 地址 EIP 返回 gcc osdev
  • 更新时间 :
  • 英文 :


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

我使用了GCC对C标准的扩展:作为值的标签和局部标签
从文档中:可以通过一元操作符' && '获得当前函数(或包含函数)中定义的标签的地址。类型为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;改变不了什么

看起来编译器正在完全优化标签,因为没有任何代码路径通向它。我已经确认,将标签移动到return语句之前,并确保在赋值和标签之间有实际的代码,从而产生我认为是您想要的行为。下面是我用来测试的代码:

void *fork(void) {
  __label__ fork_end;
  void *test = &&fork_end;
  test++;
  fork_end:
  return test;
}

基于此,我希望您确实可以通过稍微重新处理代码路径来获得您想要的结果,以确保任何代码路径都可以到达标签点。

最新更新