Re: [PATCH] ld: pep: Stop emitting reference to the pseudo-relocator function
LIU Hao <[email protected]>
| Newsgroups | gmane.comp.gnu.mingw.w64.general,gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
在 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
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public
OpenPGP_signature.asc
(application/pgp-signature, 840 B)
-----BEGIN PGP SIGNATURE----- wsF5BAABCAAjFiEEYmSQWY4DEzq4FUs4hfveZl3ogBsFAmpU4UYFAwAAAAAACgkQhfveZl3ogBuB hg/+OJsjZWqbt/yXACnkP7HsaHVW5cWHlcjMTIJHR6KVCDoD9+uxprboiHTfbyP8HCT7aZt1+SIt kJVns6F1cCai8/wsfEixsCyN0iNyFqzTtLh5wOaJqFSYDsIanyX5AW2Tw/1WIU61vSnTxuKobxEW /0MKVZAYVkqrE6hp3bnx8u5ONm5Cj97qdnxQkKExejetffyRUAzwYNdTbe1YRCS/M7HxXj3DvkbM 0utiu7qx1c4tODQh9FC4ZDQbUizKr3nJr/fFkGJlV7EBzS1P5mZgDyAvMu2trA3WLHV1/esOG0xO R4r4L33a3IKA4lgPhGgqo3CZ9mNG2enTZs9v7qNDTmGkPjlS6URCkkTOtBLrmf740uz8BWZ3JdLp 394vImrxy8+ZQOT5RY9vFArGDMN8p/AYAykKt8d3dse6+O9g1jKEMjyzXpeubKBoIAYCQEZTjO+T mwkRdZfeJCDq/cpTAsIEAaS88A3M3DR1NmSGkEcwyam7PyiMFDWVKuiNXN4bOKDbGz5zJsL+NN9x /uwKnm9jOGQVv94paW68agblOSfpxDLWE180zwY8h9gbRqxrmIBsIFUmN9MB2Etd38FIhfyNX8Mt 1sM8wmjhU2ppRUT1V6wZ2WL3clUPSLEyD3UXXh/YWCl+iTWwhZEv2YQYR1BaPWoE8mf3cdTBLmeI x08= =3ZLT -----END PGP SIGNATURE-----