lld: [ELF][ARM] Implement support for Tag_ABI_VFP_args
The Tag_ABI_VFP_args build attribute controls the procedure call standard used for floating point parameters on ARM. The values are: 0 - Base AAPCS (FP Parameters passed in Core (Integer) registers 1 - VFP AAPCS (FP Parameters passed in FP registers) 2 - Toolchain specific (Neither Base or VFP) 3 - Compatible with all (No use of floating point parameters) If the Tag_ABI_VFP_args build attribute is missing it has an implicit value of 0. We use the attribute in two ways: * Detect a clash in calling convention between Base, VFP and Toolchain. we follow ld.bfd's lead and do not error if there is a clash between an implicit Base AAPCS caused by a missing attribute. Many projects including the hard-float (VFP AAPCS) version of glibc contain assembler files that do not use floating point but do not have Tag_ABI_VFP_args. * Set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD ELF header flag for Base or VFP AAPCS respectively. This flag is used by some ELF loaders. References: * Addenda to, and Errata in, the ABI for the ARM Architecture for Tag_ABI_VFP_args * Elf for the ARM Architecture for ELF header flags Fixes LLVM PR36009 PR: 229050 Obtained from: llvm r338377 by Peter Smith
This commit is contained in:
parent
3f006c3cbf
commit
930481b8f6
@ -97,10 +97,19 @@ ARM::ARM() {
|
||||
}
|
||||
|
||||
uint32_t ARM::calcEFlags() const {
|
||||
// The ABIFloatType is used by loaders to detect the floating point calling
|
||||
// convention.
|
||||
uint32_t ABIFloatType = 0;
|
||||
if (Config->ARMVFPArgs == ARMVFPArgKind::Base ||
|
||||
Config->ARMVFPArgs == ARMVFPArgKind::Default)
|
||||
ABIFloatType = EF_ARM_ABI_FLOAT_SOFT;
|
||||
else if (Config->ARMVFPArgs == ARMVFPArgKind::VFP)
|
||||
ABIFloatType = EF_ARM_ABI_FLOAT_HARD;
|
||||
|
||||
// We don't currently use any features incompatible with EF_ARM_EABI_VER5,
|
||||
// but we don't have any firm guarantees of conformance. Linux AArch64
|
||||
// kernels (as of 2016) require an EABI version to be set.
|
||||
return EF_ARM_EABI_VER5;
|
||||
return EF_ARM_EABI_VER5 | ABIFloatType;
|
||||
}
|
||||
|
||||
RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
|
||||
|
@ -54,6 +54,9 @@ enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
|
||||
// For --target2
|
||||
enum class Target2Policy { Abs, Rel, GotRel };
|
||||
|
||||
// For tracking ARM Float Argument PCS
|
||||
enum class ARMVFPArgKind { Default, Base, VFP, ToolChain };
|
||||
|
||||
struct SymbolVersion {
|
||||
llvm::StringRef Name;
|
||||
bool IsExternCpp;
|
||||
@ -169,6 +172,7 @@ struct Configuration {
|
||||
StripPolicy Strip;
|
||||
UnresolvedPolicy UnresolvedSymbols;
|
||||
Target2Policy Target2;
|
||||
ARMVFPArgKind ARMVFPArgs = ARMVFPArgKind::Default;
|
||||
BuildIdKind BuildId = BuildIdKind::None;
|
||||
ELFKind EKind = ELFNoneKind;
|
||||
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
|
||||
|
@ -441,6 +441,46 @@ void ObjFile<ELFT>::initializeSections(
|
||||
}
|
||||
}
|
||||
|
||||
// For ARM only, to set the EF_ARM_ABI_FLOAT_SOFT or EF_ARM_ABI_FLOAT_HARD
|
||||
// flag in the ELF Header we need to look at Tag_ABI_VFP_args to find out how
|
||||
// the input objects have been compiled.
|
||||
static void updateARMVFPArgs(const ARMAttributeParser &Attributes,
|
||||
const InputFile *F) {
|
||||
if (!Attributes.hasAttribute(ARMBuildAttrs::ABI_VFP_args))
|
||||
// If an ABI tag isn't present then it is implicitly given the value of 0
|
||||
// which maps to ARMBuildAttrs::BaseAAPCS. However many assembler files,
|
||||
// including some in glibc that don't use FP args (and should have value 3)
|
||||
// don't have the attribute so we do not consider an implicit value of 0
|
||||
// as a clash.
|
||||
return;
|
||||
|
||||
unsigned VFPArgs = Attributes.getAttributeValue(ARMBuildAttrs::ABI_VFP_args);
|
||||
ARMVFPArgKind Arg;
|
||||
switch (VFPArgs) {
|
||||
case ARMBuildAttrs::BaseAAPCS:
|
||||
Arg = ARMVFPArgKind::Base;
|
||||
break;
|
||||
case ARMBuildAttrs::HardFPAAPCS:
|
||||
Arg = ARMVFPArgKind::VFP;
|
||||
break;
|
||||
case ARMBuildAttrs::ToolChainFPPCS:
|
||||
// Tool chain specific convention that conforms to neither AAPCS variant.
|
||||
Arg = ARMVFPArgKind::ToolChain;
|
||||
break;
|
||||
case ARMBuildAttrs::CompatibleFPAAPCS:
|
||||
// Object compatible with all conventions.
|
||||
return;
|
||||
default:
|
||||
error(toString(F) + ": unknown Tag_ABI_VFP_args value: " + Twine(VFPArgs));
|
||||
return;
|
||||
}
|
||||
// Follow ld.bfd and error if there is a mix of calling conventions.
|
||||
if (Config->ARMVFPArgs != Arg && Config->ARMVFPArgs != ARMVFPArgKind::Default)
|
||||
error(toString(F) + ": incompatible Tag_ABI_VFP_args");
|
||||
else
|
||||
Config->ARMVFPArgs = Arg;
|
||||
}
|
||||
|
||||
// The ARM support in lld makes some use of instructions that are not available
|
||||
// on all ARM architectures. Namely:
|
||||
// - Use of BLX instruction for interworking between ARM and Thumb state.
|
||||
@ -520,6 +560,8 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||
ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec));
|
||||
Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind);
|
||||
updateSupportedARMFeatures(Attributes);
|
||||
updateARMVFPArgs(Attributes, this);
|
||||
|
||||
// FIXME: Retain the first attribute section we see. The eglibc ARM
|
||||
// dynamic loaders require the presence of an attribute section for dlopen
|
||||
// to work. In a full implementation we would merge all attribute sections.
|
||||
|
Loading…
x
Reference in New Issue
Block a user