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

GCC - Label address return current EIP rather than real label address

在尝试编写 OS 时,我需要获取当前函数的结束地址(就在结语之前)以进行任务切换。
具体来说,我的问题是让一个 EIP 分配给我在复制的堆栈中新创建的任务(进程)。我已经设法 save/restore 注册了一个进程,但我需要找到子进程在其 EIP 中的价值。

我使用了 GCC 对 C 标准的扩展:Labels as Values and Local Labels
从文档中:您可以使用一元运算符“&&”获取当前函数(或包含函数)中定义的标签的地址。该值的类型为 void *.
and : 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    [=12=]x105008,%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;
}

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