ld: pep: Stop emitting reference to the pseudo-relocator function
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
The exported _pei386_runtime_relocator function currently only exists as
a non-functional stub in the Cygwin runtime, merely to satisfy this
reference synthesized in ld [1].
The function still has contents in the MinGW runtime [2], but is already
referenced by being explcitly called at crt startup/dll load.
We'd like to drop the (slightly confusing) stub from the Cygwin runtime,
especially in possible future architectures (e.g aarch64), where
backwards compatibilty concerns don't exist.
So, for PE+ targets, stop explicitly emitting a reference to
_pei386_runtime_relocator in the linker.
(The archeological record is unclear why this functionality exists in
ld.
Since --enable-runtime-pseudo-reloc-v1 exists for 32-bit PE arches, and
out of an abundance of caution, keep emitting it for those targets (i.e.
i386) where it conceivably might still be needed or useful with an
ancient runtime.)
Cc'ed to mingw-w64-public list.
[1] https://cygwin.com/cgit/newlib-cygwin/tree/winsup/cygwin/lib/pseudo-reloc-dummy.c
[2] https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/crt/pseudo-reloc.c#l479
Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
Cc: mingw-w64-public@lists.sourceforge.net
---
ld/pe-dll.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
Comments
在 2026-7-2 22:38, Jon Turney 写道:
> The exported _pei386_runtime_relocator function currently only exists as
> a non-functional stub in the Cygwin runtime, merely to satisfy this
> reference synthesized in ld [1].
>
> The function still has contents in the MinGW runtime [2], but is already
> referenced by being explcitly called at crt startup/dll load.
>
> We'd like to drop the (slightly confusing) stub from the Cygwin runtime,
> especially in possible future architectures (e.g aarch64), where
> backwards compatibilty concerns don't exist.
>
> So, for PE+ targets, stop explicitly emitting a reference to
> _pei386_runtime_relocator in the linker.
>
> (The archeological record is unclear why this functionality exists in
> ld.
>
> Since --enable-runtime-pseudo-reloc-v1 exists for 32-bit PE arches, and
> out of an abundance of caution, keep emitting it for those targets (i.e.
> i386) where it conceivably might still be needed or useful with an
> ancient runtime.)
>
> Cc'ed to mingw-w64-public list.
>
> [1] https://cygwin.com/cgit/newlib-cygwin/tree/winsup/cygwin/lib/pseudo-reloc-dummy.c
> [2] https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/crt/pseudo-reloc.c#l479
>
> Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
> Cc: mingw-w64-public@lists.sourceforge.net
>
AFAICT there's no reason to keep it. Even the original MinGW.org code calls it explicitly:
https://sourceforge.net/p/mingw/mingw-org-wsl/ci/5.1-trunk/tree/mingwrt/crt1.c#l343
--
Best regards,
LIU Hao
On Thu, 2 Jul 2026, LIU Hao wrote:
> 在 2026-7-2 22:38, Jon Turney 写道:
>> The exported _pei386_runtime_relocator function currently only exists as
>> a non-functional stub in the Cygwin runtime, merely to satisfy this
>> reference synthesized in ld [1].
>>
>> The function still has contents in the MinGW runtime [2], but is already
>> referenced by being explcitly called at crt startup/dll load.
>>
>> We'd like to drop the (slightly confusing) stub from the Cygwin runtime,
>> especially in possible future architectures (e.g aarch64), where
>> backwards compatibilty concerns don't exist.
>>
>> So, for PE+ targets, stop explicitly emitting a reference to
>> _pei386_runtime_relocator in the linker.
>>
>> (The archeological record is unclear why this functionality exists in
>> ld.
>>
>> Since --enable-runtime-pseudo-reloc-v1 exists for 32-bit PE arches, and
>> out of an abundance of caution, keep emitting it for those targets (i.e.
>> i386) where it conceivably might still be needed or useful with an
>> ancient runtime.)
>>
>> Cc'ed to mingw-w64-public list.
>>
>> [1]
>> https://cygwin.com/cgit/newlib-cygwin/tree/winsup/cygwin/lib/pseudo-reloc-dummy.c
>> [2]
>> https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/crt/pseudo-reloc.c#l479
>>
>> Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
>> Cc: mingw-w64-public@lists.sourceforge.net
>>
> AFAICT there's no reason to keep it. Even the original MinGW.org code calls
> it explicitly:
Yes, I think it should be safe to remove it as things stand right now.
As discussed on irc, I believe the reason why this was added in the first
place, was to try to link in the pseudo relocation machinery only when the
binary actually uses pseudo relocations.
With something like [1], the mingw-w64-crt runtime could stop calling it
unconditionally, so it only would be included when necessary. (That
wouldn't really save any notable amount of runtime, but it would save a
little bit of binary size and avoid a couple of imports, maybe shrinking
the minimal size of binaries.) But with how ld works right now, it fails
to pull in the right object files and just fails with an undefined symbol.
(And if we'd do that in mingw-w64, we'd break compatibility with existing
versions of ld, which we don't want to do lightly. And we'd have to do
a matching change to lld as well.)
So as things stand right now, I think it should be fine to drop it.
// Martin
[1] https://github.com/mstorsjo/mingw-w64/commit/pseudo-reloc-ctor
On 02.07.2026 16:38, Jon Turney wrote:
> The exported _pei386_runtime_relocator function currently only exists as
> a non-functional stub in the Cygwin runtime, merely to satisfy this
> reference synthesized in ld [1].
>
> The function still has contents in the MinGW runtime [2], but is already
> referenced by being explcitly called at crt startup/dll load.
>
> We'd like to drop the (slightly confusing) stub from the Cygwin runtime,
> especially in possible future architectures (e.g aarch64), where
> backwards compatibilty concerns don't exist.
>
> So, for PE+ targets, stop explicitly emitting a reference to
> _pei386_runtime_relocator in the linker.
This PE+ dependency is puzzling me. In a code comment near the end you
mention (only) i386, but ...
> (The archeological record is unclear why this functionality exists in
> ld.
>
> Since --enable-runtime-pseudo-reloc-v1 exists for 32-bit PE arches, and
> out of an abundance of caution, keep emitting it for those targets (i.e.
> i386) where it conceivably might still be needed or useful with an
> ancient runtime.)
... SH, MCore and Arm look to similarly retain the old behavior then. It's
really a distinction between 32-bit and 64-bit targets, and that doesn't
look like a valid criteria here.
The other aspect I'd like to understand a little better before (possibly)
ack-ing is why pseudo-relocations need producing in the first place. If
ld's generating of real relocations still isn't good enough, maybe that
wants fixing? Then the question of whether a reference to that function is
needed simply vanishes.
> @@ -2798,6 +2800,7 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED,
> return abfd;
> }
>
> +#ifndef pe_use_plus
> /* .section .rdata
> .rva __pei386_runtime_relocator */
As an aside, the name of this symbol looks to be in conflict with the
logic also applying to other architectures.
Jan
> @@ -2894,11 +2898,15 @@ pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
> link_info.output_bfd);
> add_bfd_to_link (b, bfd_get_filename (b), &link_info);
>
> + /* We think this is entirely useless, but emit a reference to the
> + relocator on the i386 target, just in case. */
> +#ifndef pe_use_plus
> if (runtime_pseudo_relocs_created++ == 0)
> {
> b = pe_create_runtime_relocator_reference (link_info.output_bfd);
> add_bfd_to_link (b, bfd_get_filename (b), &link_info);
> }
> +#endif
> }
>
> else if (addend != 0)
在 2026-7-10 20:40, Jan Beulich via Mingw-w64-public 写道:
> The other aspect I'd like to understand a little better before (possibly)
> ack-ing is why pseudo-relocations need producing in the first place. If
> ld's generating of real relocations still isn't good enough, maybe that
> wants fixing? Then the question of whether a reference to that function is
> needed simply vanishes.
It's needed by code that uses dllimport'd data without marking them `dllimport`. In C++, vtables of
polymorphic classes are also data, and there's a lot of code which doesn't apply `dllimport` to classes
(boost for example).
This makes some sense - if a header uses explicit `dllimport` then it will usually be unusable with
static libraries. Not having explicit `dllimport` enables headers to be used with either a static library
or a DLL.
When a call to a function without `dllimport` is made, the compiler generates:
call target_function
which is provided by an import library (lib*.dll.a) and effects an indirect tail call:
target_function:
jmp [rip + __imp_target_function]
x86-32 is similar, except for name decoration and address size, and the address is absolute instead of
being RIP-relative.
And when a call to a function with `dllimport`, the compiler doesn't go through the thunk, and it just
generates:
call [rip + __imp_target_function]
As for dllimport'd data, given C code:
extern int plain_data[];
int get_plain_data_1(void) { return plain_data[1]; }
__declspec(dllimport) extern int dllimp_data[];
int get_dllimp_data_1(void) { return dllimp_data[1]; }
Compiling this with `gcc test.c -O2 -mcmodel=small -S` gives:
get_plain_data_1:
mov eax, [rip + plain_data + 0x4] # eax = plain_data [1]
ret
get_dllimp_data_1:
mov rax, [rip + __imp_dllimp_data] # rax = __imp_dllimp_data
mov eax, [rax + 0x4] # eax = *(int*) (rax+4)
# = (*__imp_dllimp_data) [1]
ret
`get_plain_data_1` references the relocation `plain_data + 0x4` which is not dllimport'able; and the
linker is not able to rewrite it to the latter, which would take more space.
This is solved in three steps. First, by default (mingw-w64 GCC without `-mcmodel=small`, or Clang
without `-fno-auto-import`) the compiler must always reference a datum outside the current translation
unit through a level of indirection. Compiling the above example with `gcc test.c -O2 -S` gives:
get_plain_data_1:
mov rax, [rip + .refptr.plain_data] # rax = .refptr.plain_data
mov eax, [rax + 4] # eax = *(int*) (rax+4)
# = (*.refptr.plain_data) [1]
ret
As on x86-64 the 32-bit displacement is incapable of covering the full 64-bit address space, this level
of indirection allows access of an arbitrary 64-bit address.
Second, with `--enable-auto-import`, the linker sets `.refptr.plain_data` to `&__imp_plain_data` (the
address of `__imp_plain_data`), and generates pseudo-relocation information for it.
And finally, `_pei386_runtime_relocator()` (despite its name) in mingw-w64 CRT reads the
pseudo-relocation information, and sets `.refptr.plain_data` to the value in `__imp_plain_data`, which is
the absolute address of the imported datum in the DLL. User code can now access the datum through
`.refptr.plain_data`.
(I have omitted some details in here; what `_pei386_runtime_relocator()` actually does is
`.refptr.plain_data += __imp_plain_data - &__imp_plain_data`. Initially `.refptr.plain_data` has a value
of `&__imp_plain_data` so this can be simplified to `.refptr.plain_data = __imp_plain_data`.)
--
Best regards,
LIU Hao
@@ -170,7 +170,9 @@ static struct bfd_section *edata_s, *reloc_s;
static unsigned char *edata_d, *reloc_d;
static unsigned char *reloc_d = NULL;
static size_t edata_sz, reloc_sz = 0;
+#ifndef pe_use_plus
static int runtime_pseudo_relocs_created = 0;
+#endif
static bool runtime_pseudp_reloc_v2_init = false;
typedef struct
@@ -1773,7 +1775,7 @@ generate_reloc (bfd *abfd, struct bfd_link_info *info)
/* This can happen for example when LTO has eliminated all code. */
if (total_relocs == 0)
return;
-
+
/* At this point, we have total_relocs relocation addresses in
reloc_addresses, which are all suitable for the .reloc section.
We must now create the new sections. */
@@ -2798,6 +2800,7 @@ make_runtime_pseudo_reloc (const char *name ATTRIBUTE_UNUSED,
return abfd;
}
+#ifndef pe_use_plus
/* .section .rdata
.rva __pei386_runtime_relocator */
@@ -2841,6 +2844,7 @@ pe_create_runtime_relocator_reference (bfd *parent)
bfd_make_readable (abfd);
return abfd;
}
+#endif
void
pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
@@ -2894,11 +2898,15 @@ pe_create_import_fixup (arelent *rel, asection *s, bfd_vma addend, char *name,
link_info.output_bfd);
add_bfd_to_link (b, bfd_get_filename (b), &link_info);
+ /* We think this is entirely useless, but emit a reference to the
+ relocator on the i386 target, just in case. */
+#ifndef pe_use_plus
if (runtime_pseudo_relocs_created++ == 0)
{
b = pe_create_runtime_relocator_reference (link_info.output_bfd);
add_bfd_to_link (b, bfd_get_filename (b), &link_info);
}
+#endif
}
else if (addend != 0)