[PATCH] D31528: [ELF][MIPS] Multi-GOT implementation

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Mon May 29 16:33:00 PDT 2017


> Almost all entries inside MIPS GOT are referenced by signed 16-bit index. Zero entry lies approximately in the middle of the GOT. So the total number of GOT entries cannot exceed ~16384 for 32-bit architecture and ~8192 for 64-bit architecture. This limitation makes impossible to link rather large application like for example LLVM+Clang. There are two workaround for this problem. The first one is using the `-mxgot` compiler's flag. It enables using a 32-bit index to access GOT entries. But each access requires two assembly instructions two load GOT entry index to a register. Another workaround is multi-GOT. This patch implements it.

So, why is two instructions that bad?

With aarch64 for example we compile

extern int foo;
int *bar() {return &foo;}

To

        adrp    x0, :got:foo
        ldr     x0, [x0, :got_lo12:foo]
        ret

Or do you mean something else?

> Dynamic linker does not know anything about secondary GOTs and cannot use a regular MIPS mechanism for GOT entries initialization. So we have to use an approach accepted by other architectures and create dynamic relocations R_MIPS_REL32 to initialize global entries (and local in case of PIC code) in secondary GOTs. But ironically MIPS dynamic linker requires GOT entries and correspondingly ordered dynamic symbol table entries to deal with dynamic relocations. To handle this problem relocation-only section in the primary GOT contains entries for all symbols referenced in global parts of secondary GOTs. Although the sum of local and normal global entries of the primary got should be less than 64K, the size of the primary got (including relocation-only entries can be greater than 64K, because parts of the primary got that overflow the 64K limit are used only by the dynamic linker at dynamic link-time and not by 16-bit gp-relative addressing at run-time.
>
> The patch affects common LLD code in the following places:
>
> - Added new hidden `-mips-got-size` flag. This flag required to set low maximum size of a single GOT to be able to test the implementation using small test cases.
> - Added `InputFile` argument to the `getRelocTargetVA` function. The same symbol referenced by GOT relocation from different input file might be allocated in different GOT. So result of relocation depends on the file.

Why is this based on the InputFile? Since the register is setup in each
function header a InputSection should do, no?

I wonder if we can isolate the mips complexity somehow. Would it be
possible to create a plain got without any mips logic and then have a
function that:

* Removes dynamic relocations that were populating gon entries.
* Add got entries that are needed because of relocations.
* Replaces the plain got section with as many mips got sections as
  needed.

The change to DynamicReloc in particular is confusing. Can you expand on
why it is necessary?

Cheers,
Rafael


More information about the llvm-commits mailing list