[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-bugs
Subject: [Bug c/101275] New: [RISCV] Document the machine constraint 'S' and make it non-internal
From: i at maskray dot me via Gcc-bugs <gcc-bugs () gcc ! gnu ! org>
Date: 2021-06-30 23:01:25
Message-ID: bug-101275-4 () http ! gcc ! gnu ! org/bugzilla/
[Download RAW message or body]
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101275
Bug ID: 101275
Summary: [RISCV] Document the machine constraint 'S' and make
it non-internal
Product: gcc
Version: 11.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: i at maskray dot me
Target Milestone: ---
An absolute symbolic operand is useful in inline asm. In aarch64 and x86-64,
there is a documented (supported) approach.
// aarch64
// 'S' is documented on
https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints
extern int var;
void *addr() { return &var; }
void *addr_via_asm() {
void *ret;
asm("adrp %0, %1\nadd %0, %0, :lo12:%1" : "=r"(ret) : "S"(&var));
return ret;
}
// x86-64
// https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#x86-Operand-Modifiers
// 'P' is useful in some cases.
extern int var;
void *addr() { return &var; }
void *addr_via_asm() {
void *ret;
asm("movl %1, %k0" : "=r"(ret) : "i"(&var));
return ret;
}
For riscv there is no supported approach. The following code works
// riscv
extern int var;
void *addr() { return &var; }
void *addr_via_asm() {
void *ret;
asm("lui %0, %%hi(%1)\naddi %0,%0,%%lo(%1)" : "=r"(ret) : "S"(&var));
return ret;
}
but it uses the internal/undocumented constraint "S"
// gcc/config/riscv/constraints.md
(define_constraint "S"
"@internal
A constant call address."
(match_operand 0 "absolute_symbolic_operand"))
I hope this can made supported/documented/non-internal.
---
Why do I want this?
In the Linux kernel, arch/riscv/include/asm/vdso.h defines
/*
* The VDSO symbols are mapped into Linux so we can just use regular symbol
* addressing to get their offsets in userspace. The symbols are mapped at
an
* offset of 0, but since the linker must support setting weak undefined
* symbols to the absolute address 0 it also happens to support other low
* addresses even when the code model suggests those low addresses would not
* otherwise be availiable.
*/
#define VDSO_SYMBOL(base, name)
\
({
\
extern const char __vdso_##name[];
\
(void __user *)((unsigned long)(base) + __vdso_##name);
\
})
arch/riscv/kernel/signal.c has
regs->ra = (unsigned long)VDSO_SYMBOL(
current->mm->context.vdso, rt_sigreturn);
The file is compiled with -fno-PIE -mcmodel=medany. Because of medany, auipc is
generated:
36e: 00000697 auipc a3,0x0
36e: R_RISCV_PCREL_HI20 __vdso_rt_sigreturn
36e: R_RISCV_RELAX *ABS*
372: 00068693 mv a3,a3
At link time, auipc/mv (PC-relative) is rewritten as lui/addi (absolute):
ffffffe000201880: 000016b7 lui a3,0x1
ffffffe000201884: 80068693 addi a3,a3,-2048 # 800
<__vdso_rt_sigreturn>
The absolute address is needed for correctness. With PC-relative insns, the
runtime address will be different from its link-time address and
current->mm->context.vdso + __vdso_rt_sigreturn will be wrong.
It is fragile to rely on linker instruction rewritting (part of linker
relaxation) to do this correctness related stuff!=
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic