Re: Fwd: [PATCH v2] PE/COFF: Implement visibility attribute via .drectve

LIU Hao <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
在 2026-8-9 22:45, Oleg Tolmatcev 写道:
> ---------- Forwarded message ---------
> От: Oleg Tolmatcev <[email protected]>
> Date: вс, 9 авг. 2026 г. в 16:43
> Subject: [PATCH v2] PE/COFF: Implement visibility attribute via .drectve
> To: <[email protected]>
> Cc: Oleg Tolmatcev <[email protected]>
> 
> 
> On PE/COFF targets (MinGW, Cygwin), the visibility attribute was
> previously ignored with a warning.  This patch makes it functional
> by emitting -exclude-symbols directives into the .drectve section,
> matching Clang's behavior.  The GNU linker already reads and
> respects these directives during auto-export, so hidden/internal
> symbols are now correctly excluded from DLL exports.
> 
> gcc/ChangeLog:
> 
>          * config/mingw/winnt.cc (i386_pe_drectve_name): New.
>          (i386_pe_assemble_visibility): Emit -exclude-symbols
>          directives into .drectve for VISIBILITY_HIDDEN and
>          VISIBILITY_INTERNAL instead of warning.  Use the external
>          symbol spelling for 32-bit PE names.
> 
> gcc/testsuite/ChangeLog:
> 
>          * gcc.target/i386/visibility-hidden-mingw.c: New test.
>          * gcc.target/i386/visibility-hidden-mingw-32.c: New test.
> 
> Signed-off-by: Oleg Tolmatcev <[email protected]>
> ---
>   gcc/config/mingw/winnt.cc                     | 38 +++++++++++++++----
>   .../i386/visibility-hidden-mingw-32.c         | 12 ++++++
>   .../gcc.target/i386/visibility-hidden-mingw.c | 24 ++++++++++++
>   3 files changed, 66 insertions(+), 8 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.target/i386/visibility-hidden-mingw-32.c
>   create mode 100644 gcc/testsuite/gcc.target/i386/visibility-hidden-mingw.c
> 
> diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc
> index 66d7450652..2e06b0e814 100644
> --- a/gcc/config/mingw/winnt.cc
> +++ b/gcc/config/mingw/winnt.cc
> @@ -254,20 +254,42 @@ i386_pe_maybe_mangle_decl_assembler_name (tree
> decl, tree id)
> 
>   #endif
> 
> +/* Return the symbol spelling used by .drectve exclude-symbols directives.
> +   This is the external name without the user label prefix, while preserving
> +   calling-convention decoration such as fastcall's leading '@' or a
> +   stdcall suffix.  */
> +
> +static const char *
> +i386_pe_drectve_name (tree id)
> +{
> +  const char *name = targetm.strip_name_encoding (IDENTIFIER_POINTER (id));
> +  size_t prefix_len = strlen (user_label_prefix);
> +
> +  if (prefix_len != 0
> +      && strncmp (name, user_label_prefix, prefix_len) == 0)
> +    name += prefix_len;
> +
> +  return name;
> +}
> +
>   /* Emit an assembler directive to set symbol for DECL visibility to
>      the visibility type VIS, which must not be VISIBILITY_DEFAULT.
> -   As for PE there is no hidden support in gas, we just warn for
> -   user-specified visibility attributes.  */
> +   Emit a -exclude-symbols directive into .drectve, compatible with
> +   what Clang emits for hidden visibility on PE/COFF.  */
> 
>   void
> -i386_pe_assemble_visibility (tree decl, int)
> +i386_pe_assemble_visibility (tree decl, int vis)
>   {
> -  if (!decl
> -      || !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
> +  if (!decl)
>       return;
> -  if (!DECL_ARTIFICIAL (decl))
> -    warning (OPT_Wattributes, "visibility attribute not supported "
> -                             "in this configuration; ignored");
> +
> +  if (vis == VISIBILITY_HIDDEN || vis == VISIBILITY_INTERNAL)
> +    {
> +      tree id = DECL_ASSEMBLER_NAME (decl);
> +      const char *name = i386_pe_drectve_name (id);
> +      drectve_section ();
> +      fprintf (asm_out_file, "\t.ascii \" -exclude-symbols:%s\"\n", name);
> +    }
>   }
> 
>   #if !defined (TARGET_AARCH64_MS_ABI)
> diff --git a/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw-32.c
> b/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw-32.c
> new file mode 100644
> index 0000000000..a952c71a01
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw-32.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile { target i?86-*-mingw32* i?86-*-cygwin* } } */
> +/* { dg-options "-fvisibility=hidden" } */
> +
> +void some_cdecl (int, int) {}
> +void __attribute__((stdcall)) some_stdcall (int, int) {}
> +void __attribute__((fastcall)) some_fastcall (int, int) {}
> +
> +/* Hidden visibility on 32-bit PE/COFF drops the user label prefix in
> +   .drectve, but keeps stdcall and fastcall decoration.  */
> +/* { dg-final { scan-assembler {-exclude-symbols:some_cdecl} } } */
> +/* { dg-final { scan-assembler {-exclude-symbols:some_stdcall@8} } } */
> +/* { dg-final { scan-assembler {-exclude-symbols:@some_fastcall@8} } } */
> diff --git a/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw.c
> b/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw.c
> new file mode 100644
> index 0000000000..12d792631d
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/visibility-hidden-mingw.c
> @@ -0,0 +1,24 @@
> +/* { dg-do link { target *-*-mingw* *-*-cygwin* } } */
> +/* { dg-require-dll "" } */
> +/* { dg-options "-shared -fvisibility=hidden
> -Wl,--output-def,visibility-hidden-mingw.def" } */
> +
> +void __attribute__((visibility("default"))) exported_func(void) {}
> +void hidden_func(void) {}
> +void __attribute__((visibility("hidden"))) explicit_hidden_func(void) {}
> +void __attribute__((visibility("internal"))) internal_func(void) {}
> +
> +/* exported_func has default visibility, so it should be exported.  */
> +/* { dg-final { scan-file visibility-hidden-mingw.def
> "(?n)^\\s*exported_func(?:\\s+@\[0-9\]+)?$" } } */
> +
> +/* hidden_func gets hidden from -fvisibility=hidden, so it should not be
> +   auto-exported.  */
> +/* { dg-final { scan-file-not visibility-hidden-mingw.def
> "(?n)^\\s*hidden_func(?:\\s+@\[0-9\]+)?$" } } */
> +
> +/* explicit_hidden_func is explicitly hidden, so it should not be
> +   auto-exported.  */
> +/* { dg-final { scan-file-not visibility-hidden-mingw.def
> "(?n)^\\s*explicit_hidden_func(?:\\s+@\[0-9\]+)?$" } } */
> +
> +/* internal_func has internal visibility, so it should not be
> auto-exported.  */
> +/* { dg-final { scan-file-not visibility-hidden-mingw.def
> "(?n)^\\s*internal_func(?:\\s+@\[0-9\]+)?$" } } */
> +
> +/* { dg-final { remove-build-file "visibility-hidden-mingw.def" } } */
> --
> 2.55.0.windows.3

I have tested this change on {x86_64,i686}-w64-mingw32 and both look good to me. Thanks.





-- 
Best regards,
LIU Hao
OpenPGP_signature.asc (application/pgp-signature, 840 B)
-----BEGIN PGP SIGNATURE-----

wsF5BAABCAAjFiEEYmSQWY4DEzq4FUs4hfveZl3ogBsFAmp5qJAFAwAAAAAACgkQhfveZl3ogBt/
EQ//YDvdlSJ8qQ5wfwrD6nCwcUizy3D9/aF0oIF98NQtmJeKeFV60IY4vmU1zepqXAI+icWzRU6U
KUzZBMm0f29MPnpi3/jrpq79Cn+Pf5CUw+YIksiuFlcOn24Y+CfGdgwplZnWyzNXwnTyzor8OYV0
ykcC32QTGQJEsZTyh2MlE8NFJh6hooxmuRAJ4cAGmr3bCfsjKxae1o4JKjjFTGo2gzBPqcq4Mxfu
abwJGSKEUTOiEm+5+xJWku3m9ApLfn7Dpm2tsW5sB61xZd9yUBuOxyxrG+cqkVCeI53ZwK0kWY3z
KwdYAGoXzqSZwUHusZFZzIYuk9WaT1/Thi5twqVytOr2ZyGLDbpAI5XwnpyRZbO+CmqYOjaK4Bt6
n1LCCUlDCpwGWDl5AYxktUoFwI1ex+Z5SBzSnn10A1reGBD4wMnmHiU8dEPxgE8Q16lzxc64MZdL
PhYhsdCahX/sOr5ku3Aro35N9DCOTxrjeWS+FU0gI0lIp7EsSUhyyRiyPu/ILQA9qXviEB0EHwTO
VlG1MLYsC1nPvS3TqUVGueLqoAwr6uoipEjXFCwuK0HFC6SBtWFA3j7T+gcBnN51m3hC8pxgi9HN
euMHFncb701K3tLwvlV4w3czjtgpq5tMI6DnMCmC+8YxElGk+lbIuinpObhHGnVDaXCTtH6PezzR
/T8=
=odGb
-----END PGP SIGNATURE-----
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.