Search code examples
cgccmingwportable-executablerelocation

How to get rid of DLL .reloc section using MinGW-gcc?


I'm building vtables by hand in C. When exported from a DLL, they generate a lot of entries in its relocation table.
Sample objdump output:

Virtual Address: 00002000 Chunk size 24 (0x18) Number of fixups 8
    reloc    0 offset    0 [2000] HIGHLOW
    reloc    1 offset    4 [2004] HIGHLOW
    reloc    2 offset    8 [2008] HIGHLOW
    reloc    3 offset    c [200c] HIGHLOW
    reloc    4 offset   10 [2010] HIGHLOW
    reloc    5 offset   14 [2014] HIGHLOW
    reloc    6 offset   18 [2018] HIGHLOW
    reloc    7 offset   1c [201c] HIGHLOW

Is there any way to get rid of them, or are they the only way on Windows?
These are my findings so far:

  1. in Visual Studio's link, there is the option /FIXED (which does exactly what I want)
  2. there is this tuturial, but most of it seems to apply to gcc under Linux only
  3. I can build the DLL without -shared and instead set --image-base

The last one works indeed (no .reloc section is generated), but I consider this an extreme ugly hack, because then it's actually no DLL anymore.

Clarification:

I get the impression that this question is only downvoted because people find relocations are a good thing. I admit, they are good in general but I have a very specific objective. I want to show how dynamic polymorphism with vtables can be achieved in O(1), like so:

struct IDerived {
    union {
        IBaseA asBaseA;
        struct {
            int (*foo)(Derived this); // inherited from BaseA
            ...
        };
    };
    union {
        IBaseB asBaseB;
        struct {
            int (*bar)(Derived this); // inherited from BaseB
            ...
        };
    };
    int (*baz)(Derived this);
    ...
};

struct Derived {
    const IDerived *iface;
    void *data;
};

extern void doSthWithBaseB(BaseB x);

void doSthWithDerived(Derived x) {
    x.iface->foo(x);
    doSthWithBaseB((BaseB){ &x.iface->asBaseB, x.data }) // high-level cast
}

As the "high-level cast" only involves pointer arithmetic, this is O(1) (especially, no linear search is done like in Java).

Now back to relocations: No matter how low the cost is, it happens to be O(n), since every method in every class needs to be updated. Sigh.

tl;dr
Is there a pendant to Microsoft's /FIXED for GCC? If not, what flags are to be set in the PE to achieve the desired behaviour?


Solution

  • Okay, I found an answer myself:

    One has to use strip -R .reloc on the DLL and then manually add IMAGE_FILE_RELOCS_STRIPPED (0x0001) to the Characteristics field in the PE header. That will do it.

    This is to be used with a custom base address (-Wl,--image-base=...) of course – otherwise Windows won't be able to load the DLL.
    The resulting module may also be a false positive for antivirus software (and thus be moved to the container right away).