PIC and mcmodel=large on x86 doesn't use any relocations

Message: 2
Date: Sat, 29 Oct 2016 22:36:41 +0200
From: Joerg Sonnenberger via llvm-dev <llvm-dev@lists.llvm.org>
To: llvm-dev@lists.llvm.org
Subject: Re: [llvm-dev] PIC and mcmodel=large on x86 doesn't use any
Message-ID: <20161029203641.GB20270@britannica.bec.de>
Content-Type: text/plain; charset=us-ascii

> I want my GOT, .plt, and other static data to be more than 2GB away
from the code.
> Our stack and heap will also live in the bottom 2GB chunk of memory
> due to VAX history.
> No single code segment or data segment will be larger than 2GB
> however. So branches inside of .text for example (or to other code
> sections) will fit within 2GB.

Actually, it is only GOT and PLT that is really relevant. All the other
data is easy to access via GOT with the same or less overhead than
doing the 64bit movabs dance. Some platforms like PPC allow multiple
GOT and PLT sections to deal with the immediate constraints of the

Given that the PLT has to be executable, there is normally no big
justification for splitting it from the actual code segment. The GOT is
a bit more difficult, but I still don't see why you want to split that
off? The pain is large for mandating that to be separate.


OpenVMS on both Alpha and Itanium are mixed-sized pointer systems.
The default size is 32-bits but there are also 64-bit interfaces.

Some of our languages have 64-bit pointers, but some do not. They
still are VAX-era languages which believe you can hold a pointer to
a routine in a 32-bit longword. To have code actually in 64-bit
address space, the way we implement this on Itanium is to keep the
function descriptors and short section in 32-bit space. The
address of a "routine" is the address of its function descriptor
since you need both the code address and the GP value to call the
routine. (Yes, our linker does something slightly non-standard
with the DIR32LSB/DIR64LSB relocations by treating them as
FPTR32LSB/FPTR64LSB for STT_FUNCs so you can actually never obtain
the code address via linker relocation).

The idea to make this all work on x86-64 is to use the address of
a routine's PLT as its "address" in all cases. By putting the PLT
in 32-bit address space, some ancient BASIC or Fortran program can
continue to use an INTEGER*4 to hold a routine's "address" and pass
it around. Of course, our PLTs won't be actual dynamic loading
code but just trampolines to the 64-bit code. The PLTs provide
a consistent "address of routine" for pointer comparisons, etc just
like the "primary function descriptor" on Itanium.


That's effectively how the main binary works for dynamically linked
non-PIE x86_64 code in the default code model. It creates some problems
for protected symbols and involves the nasty copy relocations, but
nothing so far seems to require the large code model, at least in the
sense of "GOT and PLT are not addressable with 32bit signed offset"?