Aerath Aerath - 11 months ago 53
C Question

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

In an attempt to write an OS, I need to get the address of the current function's end (right before epilogue) for task switching.

Concretely my problem is to get an EIP to assign to my newly created task (process) inside the copied stack. I have already managed to save/restore registers for a process, but I need to find what value the child process will have in it's EIP.

I used GCC's extensions to C standard : Labels as Values and Local Labels

From the documentation : You can get the address of a label defined in the current function (or a containing function) with the unary operator ‘&&’. The value has type void *.

and : GCC allows you to declare local labels in any nested block scope. A local label is just like an ordinary label, but you can only reference it (with a goto statement, or by taking its address) within the block in which it is declared.

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

GCC does compile it, with just warnings about non-standard code.

However when disassembled, gdb shows :

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

I expect
task->regs.eip = (uintptr_t)&&fork_endl
to save
rather than

-O0 -std=gnu99 -fgnu89-inline -DDEBUG -ggdb3 -ffreestanding -fbuiltin
(warnings related options not shown here).

__label__ fork_end;
changes nothing.

Answer Source

It appears that the compiler is optimizing out the label entirely as no code path ever leads to it. I have confirmed that moving the label to before the return statement and ensuring that there is actual code in-between the assignment and the label results in what I believe is your desired behaviour. Here is the code I put together to test:

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


  return test;

Based on this, I would expect that you can indeed get what you want by re-working your code path slightly to ensure that the label point is reachable by any code path.