1

Recetly, this function rip_rel_ptr has been added to Linux kernel. https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/asm.h#L118.

I can compile the kernel, but when I copy this function for myself,

static inline
__attribute__((__always_inline__))
__attribute__((__pure__)) void *rip_rel_ptr(void *var)
{
        asm("leaq %c1(%%rip), %0" : "=r"(var) : "i"(var));

        return var;
}

#define RIP_REL_REF(var)    (*(typeof(&(var)))rip_rel_ptr(&(var)))

int x;

int main(void)
{
        RIP_REL_REF(x);

        return 0;
}

I see this error:

a.c: In function ‘main’:
a.c:8:2: warning: ‘asm’ operand 1 probably does not match constraints
    8 |  asm("leaq %c1(%%rip), %0" : "=r"(var) : "i"(var));
      |  ^~~
a.c:8:2: error: impossible constraint in ‘asm’

I can not figure out why it compiles in the kernel on the same machine but can not compile it separately.

7
  • IDK if this is significant, but the kernel is compiled with -mcmodel=kernel; user-space programs are compiled with -fPIE (by default). I'm not sure if kernel builds also use -fPIE, but probably yes because kernel ASLR is a thing. Commented Jul 13, 2024 at 4:36
  • 1
    Looking more closely at how you're using it, are you sure kernel code uses this macro on automatic storage (non-static local variables)? The address of a local isn't a build-time constant, not even relative to the .text. I'd expect that to work with a global or static variable whose address can be obtained with a RIP-relative LEA. Commented Jul 13, 2024 at 4:36
  • 1
    Well, AFAIK, for x86, only the code in compressed kernel is compiled as position independent, the remaining is not. Commented Jul 13, 2024 at 4:43
  • 3
    Looks like you have to compile with at least -O1 optimizations and a global variable. Commented Jul 13, 2024 at 5:15
  • 3
    @MichaelPetch: Oh yeah that makes sense, you need constant-propagation through the function arg void *var to the asm statement. always_inline doesn't stop function parameters from being actual variables which (in debug mode) actually exist with their own address. (Why is this C++ wrapper class not being inlined away? - inlined yes, away no) Commented Jul 13, 2024 at 6:17

1 Answer 1

3

Are you sure kernel code uses this macro on automatic storage (non-static local variables)? The address of a local on the stack isn't a build-time constant (neither absolute nor relative to .text).

I'd expect that to work with a global or static variable, since its address can be obtained with a RIP-relative LEA. Even with ASLR, the distance between .text and static storage (.data, .bss, .rodata) is fixed at link time.

This also only works with optimization enabled; you need constant-propagation through the function arg void *var to the asm statement. always_inline doesn't stop function parameters from being actual variables which (in -O0 "debug" builds) actually exist with their own address. (Why is this C++ wrapper class not being inlined away? - inlined yes, optimized away no)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.