Hi, I want to link a small kernel to run at 0xFFFF800000000000, all text, data, bss will fit in a 2GB region. I noticed that the 2 code models that I can choose from, small and kernel, require the kernel to run in the first or last 2GB of address space, not in the middle. One option I have is large, which turns every global function call into a indirect call. The other option, of course, is small_pic, but that turns every global memory reference into 2 references, and I have to setup the GOT when loading the kernel. If all my code and data fit in 2GB, it seems like it should be possible for this 2GB to be located anywhere. But GCC seems to like to generate instructions in the form of mov $symbol, %reg where the immediate operand $symbol is a sign extended (or zero extended) 32-bit immediate, thus requiring symbol to be in the first or last 2GB of address space. If we replaced those instructions with lea symbol(%rip), %reg then the only requirement is that symbol is in the same 2GB region as the current code. Are there existing gcc options to do what I want? Is what I want even possible? Thanks, -Mike Example: extern int b[]; extern int B(int *, int); int A() { return B(b, b[0]); } Assembly emitted when with -mcmodel=kernel: movl b(%rip), %esi movq $b, %rdi # linker complains that relocation record for b doesn't fit in 32-bit jmp B With -mcmodel=large: movabsq $b, %rdi # 64-bit imm, instruction is HUGE movabsq $B, %rax movl (%rdi), %esi jmp *%rax # indirect call! With -mcmodel=small and -fpic: movq b@GOTPCREL(%rip), %rdi # extra memory reference to get &b movl (%rdi), %esi jmp B@PLT # extra memory reference to get &B, and indirect call What I want: movl b(%rip), %esi leaq b(%rip), %rdi jmp B