[PATCH] PowerPC support for the ELFv2 ABI (powerpc64le-linux)

Bill Schmidt wschmidt at linux.vnet.ibm.com
Wed Jul 16 05:27:04 PDT 2014

FWIW, I reviewed Ulrich's patches prior to posting, and they look good
to me.  Reviews from other folks are welcome!


On Mon, 2014-07-14 at 17:16 +0200, Ulrich Weigand wrote:
> Hello,
> this patch series implements support in LLVM for the PowerPC ELFv2 ABI.
> Together with a companion patch to clang (posted on cfe-commits), this
> makes clang/LLVM fully usable on powerpc64le-linux.  Overall the patch
> series passed the following testing (both on powerpc64-linux (ELFv1) and
> powerpc64le-linux (ELFv2)):
> - building LLVM & clang, running the regression test suite
> - running projects/test-suite
> - full 3-stage bootstrap of clang
> - GCC ABI compatibility test suite GCC vs. clang  [*]
> [*] There are some failures due to GCC features clang does not implement
> (or implements slightly differently than GCC, like attribute((aligned)) on
> bit field base types), but those seem platform-independent, and are the
> same on ELFv1 and ELFv2.
> I've broken up ELFv2 support into the following pieces:
> - MC support for .abiversion directive
> ELFv2 binaries are marked by a bit in the ELF header e_flags field.  A new
> assembler directive .abiversion can be used to set that flag.  This patch
> implements support in the PowerPC MC streamers to emit the .abiversion
> directive (both into assembler and ELF binary output), as well as support
> in the assembler parser to parse the .abiversion directive.
> (See attached file: diff-llvm-elfv2-abiversion)
> - MC support for .localentry directive
> A second binutils feature needed to support ELFv2 is the .localentry
> directive.  In the ELFv2 ABI, functions may have two entry points: one for
> calling the routine locally via "bl", and one for calling the function via
> function pointer (either at the source level, or implicitly via a PLT stub
> for global calls).  The two entry points share a single ELF symbol, where
> the ELF symbol address identifies the global entry point address, while the
> local entry point is found by adding a delta offset to the symbol address.
> That offset is encoded into three platform-specific bits of the ELF symbol
> st_other field.
> The .localentry directive instructs the assembler to set those fields to
> encode a particular offset.  This is typically used by a function prologue
> sequence like this:
> func:
>         addis r2, r12, (.TOC.-func)@ha
>         addi r2, r2, (.TOC.-func)@l
>         .localentry func, .-func
> Note that according to the ABI, when calling the global entry point, r12
> must be set to point the global entry point address itself; while when
> calling the local entry point, r2 must be set to point to the TOC base.
> The two instructions between the global and local entry point in the above
> example translate the first requirement into the second.
> This following patch implements support in the PowerPC MC streamers to emit
> the .localentry directive (both into assembler and ELF object output), as
> well as support in the assembler parser to parse the .localentry directive.
> In addition, there is another change required in MC fixup/relocation
> handling to properly deal with relocations targeting function symbols with
> two entry points: When the target function is known local, the MC layer
> would immediately handle the fixup by inserting the target address -- this
> is wrong, since the call may need to go to the local entry point instead.
> The GNU assembler handles this case by *not* directly resolving fixups
> targeting functions with two entry points, but always emits the relocation
> and relies on the linker to handle this case correctly.  This patch changes
> LLVM MC to do the same (this is done via the processFixupValue routine).
> Similarly, there are cases where the assembler would normally emit a
> relocation, but "simplify" it to a relocation targeting a *section* instead
> of the actual symbol.  For the same reason as above, this may be wrong when
> the target symbol has two entry points.  The GNU assembler again handles
> this case by not performing this simplification in that case, but leaving
> the relocation targeting the full symbol, which is then resolved by the
> linker.  This patch changes LLVM MC to do the same (the
> needsRelocateWithSymbol routine).   NOTE: the LLVM code is actually overly
> pessimistic, since the needsRelocateWithSymbol routine currently does not
> have access to the actual target symbol, and thus must always assume that
> it might have two entry points.  This can be improved upon by modifying
> common code to pass the target symbol when calling needsRelocateWithSymbol
> (probably best done as a follow-on patch).
> (See attached file: diff-llvm-elfv2-localentry)
> - ELFv2 function call changes: two entry points instead of function
> descriptors
> This patch build upon the two preceding MC changes to implement the basic
> ELFv2 function call convention.  In the ELFv1 ABI, a "function descriptor"
> was associated with every function, pointing to both the entry address and
> the related TOC base (and a static chain pointer for nested functions).
> Function pointers would actually refer to that descriptor, and the indirect
> call sequence needed to load up both entry address and TOC base.
> In the ELFv2 ABI, there are no more function descriptors, and function
> pointers simply refer to the (global) entry point of the function code.
> Indirect function calls simply branch to that address, after loading it up
> into r12 (as required by the ABI rules for a global entry point).  Direct
> function calls continue to just do a "bl" to the target symbol; this will
> be resolved by the linker to the local entry point of the target function
> if it is local, and to a PLT stub if it is global.  That PLT stub would
> then load the (global) entry point address of the final target into r12 and
> branch to it.  Note that when performing a local function call, r2 must be
> set up to point to the current TOC base: if the target ends up local, the
> ABI requires that its local entry point is called with r2 set up; if the
> target ends up global, the PLT stub requires that r2 is set up.
> This patch implements all LLVM changes to implement that scheme:
> - No longer create a function descriptor when emitting a function
> definition (in EmitFunctionEntryLabel)
> - Emit two entry points *if* the function needs the TOC base (r2) anywhere
> (this is done EmitFunctionBodyStart; note that this cannot be done in
> EmitFunctionBodyStart because the global entry point prologue code must be
> *part* of the function as covered by debug info).
> - In order to make use tracking of r2 (as needed above) work correctly,
> mark direct function calls as implicitly using r2.
> - Implement the ELFv2 indirect function call sequence (no function
> descriptors; load target address into r12).
> - When creating an ELFv2 object file, emit the .abiversion 2 directive to
> tell the linker to create the appropriate version of PLT stubs.
> Note that all this is triggered by a predicate isELFv2ABI.  This is
> currently hard-coded to be true iff the "little-endian 64-bit
> SVR4" (ppc64le) triple is selected.  To be fully compatible with GCC, we
> should really implement the -mabi=elfv1 / -mabi=elfv2 option pair and
> support both ELFv1 and ELFv2 on both powerpc64-linux and powerpc64le-linux
> targets, with big-endian defaulting to ELFv1 and little-endian defaulting
> to ELFv2.  However, since the BE ELFv2 and LE ELFv1 case are only
> theoretical options at this point (there's no library support for those in
> any current or planned Linux distribution), I haven't implemented this yet.
> It should be straightforward to add this support as a follow-on patch by
> just implementing the option machinery and hooking it up to the isELFv2ABI
> predicate.
> (See attached file: diff-llvm-elfv2-funcdesc)
> - ELFv2 stack space reductions
> The ELFv2 ABI reduces the amount of stack required to implement an
> ABI-compliant function call in two ways:
> * the "linkage area" is reduced from 48 bytes to 32 bytes by eliminating
> two unused doublewords
> * the 64-byte "parameter save area" is now optional and need not be present
> in certain cases
>    (it remains mandatory in functions with variable arguments, and
> functions that have any parameter that is passed on the stack)
> The following patch implements this required changes:
> - reducing the linkage area, and associated relocation of the TOC save
> slot, in getLinkageSize / getTOCSaveOffset
>   (this requires updating all callers of these routines to pass in the
> isELFv2ABI flag).
> - (partially) handling the case where the parameter save are is optional
> This latter part requires some extra explanation:  Currently, we still
> always allocate the parameter save area when *calling* a function.  That is
> certainly always compliant with the ABI, but may cause code to allocate
> stack unnecessarily.  This can be addressed by a follow-on optimization
> patch.
> On the *callee* side, in LowerFormalArguments, we *must* track correctly
> whether the ABI guarantees that the caller has allocated the parameter save
> area for our use, and the patch does so. However, there is one
> complication: the code that handles incoming "byval" arguments will
> currently *always* write to the parameter save area, because it has to
> force incoming register arguments to the stack since it must return an
> *address* to implement the byval semantics.  This is already inefficient in
> some cases in the ELFv1 ABI, but in the ELFv2 ABI it would be actually
> buggy since it would write to the argument save area that the caller
> actually did *not* allocate.
> There are two options to fix this: One would be that the
> LowerFormalArguments code could keep its overall logic, except it writes
> arguments to a freshly allocated stack slot on the function's own stack
> frame instead of the argument save area in those cases where that area is
> not present.  I chose *not* to implement this, since writing arguments that
> already fit fully in registers to the stack *is* inefficient.  Instead I
> chose the second option: have the front-end pass such arguments in a way
> that does *not* use the "byval" scheme in the first place.  This is
> implemented in the diff-llvm-elfv2-aggregates patch below and the
> associated clang patch.  In this patch I simply verify that if there is no
> argument save area guaranteed by the ABI, we have no byval arguments, and
> report a fatal LLVM ERROR otherwise.   This unfortunately makes the
> platform-independent DebugInfo/2010-10-01-crash.ll case fail since it uses
> a byval parameter in a way that is now unsupported.
> (See attached file: diff-llvm-elfv2-stack)
> - ELFv2 explicit CFI for CR fields
> This is a minor improvement in the ELFv2 ABI.   In ELFv1, DWARF CFI would
> represent a saved CR word (holding CR fields CR2, CR3, and CR4) using just
> a single CFI record refering to CR2.   In ELFv2 instead, each of the CR
> fields is represented by its own CFI record.  The advantage is that the
> compiler can now chose to save just a single (or two) CR fields instead of
> all of them, if those are the only ones that actually need saving.  That
> can lead to more efficient code using mf(o)crf instead of the (slow) mfcr
> instruction.
> Note that the following patch does not (yet) implement this more efficient
> code generation, but it does implement the part that is required to be ABI
> compliant: creating multiple CFI records if multiple CR fields are saved.
> (See attached file: diff-llvm-elfv2-crsave)
> - ELFv2 aggregate passing support
> This patch is intended to work together with the clang companion patch.
> The LLVM patch provides infrastructure that allows the clang side to
> implement the missing pieces of the ELFv2 ABI relating to aggregates passed
> by value.  Specifically, we need to:
> - pass (and return) "homogeneous" floating-point or vector aggregates in
> FPRs and VRs (this is similar to the ARM homogeneous aggregate ABI)
> - return aggregates of up to 16 bytes in one or two GPRs
> - pass aggregates that fit fully in registers without using the "byval"
> mechanism (see discussion of the diff-llvm-elfv2-stack)
> As infrastructure to enable those changes, this LLVM patch adds support for
> passing array types directly.  These can be used by the front-end to pass
> aggregate types (coerced to an appropriate array type).  The details of the
> array type being used inform the back-end about ABI-relevant properties.
> Specifically, the array element type encodes:
> - whether the parameter should be passed in FPRs, VRs, or just GPRs/stack
> slots  (for float / vector / integer element types, respectively)
> - what the alignment requirements of the parameter are when passed in
> GPRs/stack slots  (8 for float / 16 for vector / the element type size for
> integer element types) -- this corresponds to the "byval align" field
> The following patch uses the functionArgumentNeedsConsecutiveRegisters
> callback to encode that special treatment is required for all
> directly-passed array types.  The isInConsecutiveRegs /
> isInConsecutiveRegsLast bits set as a results are then used to implement
> the required size and alignment rules in CalculateStackSlotSize /
> CalculateStackSlotAlignment etc.
> As a related change, the ABI routines have to be modified to support
> passing floating-point types in GPRs.  This is necessary because with
> homogeneous aggregates of 4-byte float type we can now run out of FPRs
> *before* we run out of the 64-byte argument save area that is shadowed by
> GPRs.  Any extra floating-point arguments that no longer fit in FPRs must
> now be passed in GPRs until we run out of those too.  Note that there was
> already code to pass floating-point arguments in GPRs used with vararg
> parameters, which was done by writing the argument out to the argument save
> area first and then reloading into GPRs.  The patch re-implements this,
> however, in favor of code packing float arguments directly via
> extension/truncation, BITCAST, and BUILD_PAIR operations.  This has some
> advantages:
> - we no longer rely on the argument save area being present
> - while the BITCASTs will currently often also result in values being
> written to the stack and then reloaded, this should improve once we
> implement the Power8 GPR<->FPR move instructions.
> The final part of the patch enables up to 8 FPRs and VRs for argument
> return in PPCCallingConv.td; this is required to support returning ELFv2
> homogeneous aggregates.  (Note that this doesn't affect other ABIs since
> LLVM wil only look for which register to use if the parameter is marked as
> "direct" return anyway.)
> (See attached file: diff-llvm-elfv2-aggregates)
> - ELFv2 dynamic loader support
> This is the final piece of ELFv2 support in LLVM: it enables the new ABI in
> the runtime dynamic loader.  The loader has to implement the following
> features:
> - In the ELFv2 ABI, do not look up a function descriptor in .opd, but
> instead use the local entry point when resolving a direct call.
> - Update the TOC restore code to use the new TOC slot linkage area offset.
> - Create PLT stubs appropriate for the ELFv2 ABI.
> Note that this patch also adds common-code changes. These are necessary
> because the loader must check the newly added ELF flags: the e_flags header
> bits encoding the ABI version, and the st_other symbol table entry bits
> encoding the local entry point offset.  There is currently no way to access
> these, so I've added ObjectFile::getPlatformFlags and SymbolRef::getOther
> accessors.
> (See attached file: diff-llvm-elfv2-dyld)
> I'd appreciate any review of the patch series!   I'm aware it's a lot of
> code, but I'd really like to see clang/LLVM usable out-of-the-box on
> powercp64le-linux soon (hopefully even in 3.5)!
> Mit freundlichen Gruessen / Best Regards
> Ulrich Weigand
> --
>   Dr. Ulrich Weigand | Phone: +49-7031/16-3727
>   STSM, GNU/Linux compilers and toolchain
>   IBM Deutschland Research & Development GmbH
>   Vorsitzende des Aufsichtsrats: Martina Koederitz | Geschäftsführung: Dirk
> Wittkopp
>   Sitz der Gesellschaft: Böblingen | Registergericht: Amtsgericht
> Stuttgart, HRB 243294
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

More information about the llvm-commits mailing list