[Mingw-w64-public] [PATCH] ld: pep: Stop emitting reference to the pseudo-relocator function

LIU Hao lh_mouse@126.com
Mon Jul 13 12:59:50 GMT 2026


在 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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <https://sourceware.org/pipermail/binutils/attachments/20260713/f2eda335/attachment-0001.sig>


More information about the Binutils mailing list