I'm currently working on the syscall handler for the x86-64 port of Viengoos. Part of this is saving the running thread's register file at kernel entry.
I'd like to save this state directly into the thread's control block, which is described by a C data structure. The difficulty is determining the offset of the start of the save area: I can't use &tcb->regs to get the offset of the field in the inline assembly.
Two options come to mind. I could hard code the offsets. This is not maintainable in the long run in particular as the thread control block is not an architecture-specific data structure (and hence changes to it may not be synchronized by the author). This can be alleviated somewhat by using assertions, however, it is still a pain. Another option is to generate a header at compile time. There are some hacks to get this to work when cross compiling but I'd prefer to avoid depending on more tools.
It turns out I can convince gcc generate the constants and embed them directly into my assembly. The idea is to use a constant argument to the asm statement, which gcc folds into the assembly code. The trick is that the asm statement must be in a function; asm statements at the top-level cannot take arguments. The price of this approach is that a few instructions, which are never executed, are added to the resulting binary. No big deal.
The following illustrates the idea:
#include <stddef.h>
struct foo
{
int a[3];
int b;
};
void
foo (void)
{
asm ("mov %0, %%eax\n\t" :: "n"(offsetof (struct foo, b)));
}
This is the code that gcc generates:
$ gcc -S a.c -o a.s
$ cat a.s
.file "a.c"
.text
.globl _foo
.type _foo, @function
_foo:
pushl %ebp
movl %esp, %ebp
#APP
# 12 "a.c" 1
mov $12, %eax
# 0 "" 2
#NO_APP
popl %ebp
ret
.size _foo, .-_foo
.ident "GCC: (Debian 4.3.2-1.1) 4.3.2"
.section .note.GNU-stack,"",@progbits