Bug 105576 - x86: Support a machine constraint to get raw symbol name
Summary: x86: Support a machine constraint to get raw symbol name
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: 14.0
Assignee: Not yet assigned to anyone
URL:
Keywords: inline-asm
: 113675 (view as bug list)
Depends on:
Blocks:
 
Reported: 2022-05-12 05:30 UTC by Fangrui Song
Modified: 2024-01-31 00:15 UTC (History)
4 users (show)

See Also:
Host:
Target: x86_64-*
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fangrui Song 2022-05-12 05:30:34 UTC
An raw symbolic operand is useful in inline asm (e.g. in C++ to get the mangled name, or in C to let the compiler do some asm checking). In aarch64 and riscv, there is a documented (supported) approach.
documented on https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints

extern int var;
void *addr(void) { return &var; }
void addr_via_asm(void) {
  asm (".pushsection .xxx,\"aw\"; .dc.a %0; .popsection" :: "S"(addr)); // supported on aarch64 and riscv
  asm (".pushsection .xxx,\"aw\"; .dc.a %0; .popsection" :: "S"(&var)); // supported on aarch64
}

On x86, it is unclear which should be preferred. It seems that the operand modifier 'p' can be used for a function,
but not a variable.

asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "m"(addr));
Comment 1 Andrew Pinski 2022-05-12 06:00:00 UTC
Isn't the i constraint the one you want to be portable:

‘i’
An immediate integer operand (one with constant value) is allowed. This includes symbolic constants whose values will be known only at assembly time or later.
Comment 2 Andrew Pinski 2022-05-12 06:00:50 UTC
(In reply to Andrew Pinski from comment #1)
> Isn't the i constraint the one you want to be portable:
> 
> ‘i’
> An immediate integer operand (one with constant value) is allowed. This
> includes symbolic constants whose values will be known only at assembly time
> or later.

This is from https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#Simple-Constraints
Comment 3 Andrew Pinski 2022-05-12 06:03:50 UTC
Note integer here does allow for pointers as that is still an integer value internally.
Comment 4 Hongtao.liu 2022-05-12 06:36:55 UTC
constraint "i" + "%p0"?

  asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(addr)); // supported on aarch64 and riscv
  asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(&var)); // supported on aarch64
Comment 5 Fangrui Song 2022-05-13 17:08:56 UTC
(In reply to Hongtao.liu from comment #4)
> constraint "i" + "%p0"?
> 
>   asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(addr)); //
> supported on aarch64 and riscv
>   asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(&var)); //
> supported on aarch64

constraint "i" + "%p0" does not work with -mcmodel=large:

a.c:11:3: warning: ‘asm’ operand 0 probably does not match constraints
   11 |   asm volatile(".quad %p0" :: "i"(foo));
      |   ^~~
a.c:11:3: error: impossible constraint in ‘asm’

On aarch64, `asm volatile(".quad %0" :: "S"(foo));` works with -mcmodel=large -fno-pic (note: PIC large code model has not been implemented).
Comment 6 Fangrui Song 2023-05-05 04:53:17 UTC
(In reply to Hongtao.liu from comment #4)
> constraint "i" + "%p0"?
> 
>   asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(addr)); //
> supported on aarch64 and riscv
>   asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "i"(&var)); //
> supported on aarch64

It looks like %p0 + "i" doesn't work with -fpie or -fpic...

void k();
void foo() {
  asm("call %p0" :: "i"(k));
}
Comment 7 Julian Waters 2023-12-07 02:49:36 UTC
Strangely, the following works if compiled with optimizations enabled, -O1 and above, but not with -O0, when optimizations are disabled

[[gnu::extended(; [dispatcher] "i" (static_cast<void (*) () noexcept>([] () noexcept -> void {})); ; start)]]
asm (R"(
        .endif
        .rva %l[start], 1f, %c[dispatcher], 2f
        .seh_code
)");

With -O0 the error is

exceptions.cpp: In function 'void exceptions()':
exceptions.cpp:59:5: warning: 'asm' operand 0 probably does not match constraints
   59 |     asm (R"(
      |     ^~~
exceptions.cpp:59:5: error: impossible constraint in 'asm'

With -O1 and above, %c[dispatcher] yields:

.rva .L2, 1f, _ZZL10exceptionsvENUlPVK19_EXCEPTION_POINTERSPVKvE0_4_FUNES1_S3_, 2f
Comment 8 Fangrui Song 2024-01-11 04:00:27 UTC
I've encountered another use case related to metadata sections (establish an artificial reference for linker garbage collection purposes)

namespace ns { extern int var; }  // defined in another translation unit

void reference() {     // if this is retained, ensure var is pulled in
  asm (".reloc ., BFD_RELOC_NONE, %0" :: "S"(&ns::var));
}

Created
https://gcc.gnu.org/pipermail/gcc-patches/2024-January/642580.html
([PATCH] i386: Add "z" constraint for symbolic address/label reference [PR105576])
Comment 9 Andrew Pinski 2024-01-30 23:05:05 UTC
*** Bug 113675 has been marked as a duplicate of this bug. ***
Comment 10 GCC Commits 2024-01-30 23:21:39 UTC
The master branch has been updated by H.J. Lu <hjl@gcc.gnu.org>:

https://gcc.gnu.org/g:d7250100381b817114447d91fff4748526d4fb21

commit r14-8637-gd7250100381b817114447d91fff4748526d4fb21
Author: Fangrui Song <maskray@google.com>
Date:   Thu Jan 11 10:24:25 2024 -0800

    i386: Add "Ws" constraint for symbolic address/label reference [PR105576]
    
    Printing the raw symbol is useful in inline asm (e.g. in C++ to get the
    mangled name).  Similar constraints are available in other targets (e.g.
    "S" for aarch64/riscv, "Cs" for m68k).
    
    There isn't a good way for x86 yet, e.g. "i" doesn't work for
    PIC/-mcmodel=large.  This patch adds "Ws".  Here are possible use cases:
    
    ```
    namespace ns { extern int var; }
    asm (".pushsection .xxx,\"aw\"; .dc.a %0; .popsection" :: "Ws"(&var));
    asm (".reloc ., BFD_RELOC_NONE, %0" :: "Ws"(&var));
    ```
    
    gcc/ChangeLog:
    
            PR target/105576
            * config/i386/constraints.md: Define constraint "Ws".
            * doc/md.texi: Document it.
    
    gcc/testsuite/ChangeLog:
    
            PR target/105576
            * gcc.target/i386/asm-raw-symbol.c: New testcase.
Comment 11 Fangrui Song 2024-01-30 23:56:37 UTC
Thanks to HJ for landing the GCC patch (milestone: 15?) for me.

Note that I made a typo in the commit message. "Ws" should typically be used with the modifier 'p'

    ```
    namespace ns { extern int var; }
    asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "Ws"(&var));
    asm (".reloc ., BFD_RELOC_NONE, %p0" :: "Ws"(&var));
    ```
    
The upcoming Clang 18 release will also support "Ws".

For software utilizing this feature, for aarch64 and riscv, use the constraint "S".
Comment 12 Andrew Pinski 2024-01-31 00:15:22 UTC
(In reply to Fangrui Song from comment #11)
> Thanks to HJ for landing the GCC patch (milestone: 15?) for me.

It made into GCC 14.