forked from OSchip/llvm-project
[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 PR36009 Differential Revision: https://reviews.llvm.org/D49993 llvm-svn: 338377
This commit is contained in:
parent
4aec86d37a
commit
70997f9a4e
|
@ -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,
|
||||
|
|
|
@ -58,6 +58,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;
|
||||
|
@ -196,6 +199,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;
|
||||
|
|
|
@ -494,6 +494,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.
|
||||
|
@ -573,6 +613,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.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 0 // Tag_ABI_VFP_args = 0 (AAPCS, Base variant)
|
||||
|
||||
.syntax unified
|
||||
.global f0
|
||||
.type f0, %function
|
||||
f0: bx lr
|
|
@ -0,0 +1,16 @@
|
|||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 3 // Tag_ABI_VFP_args = 3 (Compatible with all)
|
||||
|
||||
.syntax unified
|
||||
.global f3
|
||||
.type f3, %function
|
||||
f3: bx lr
|
|
@ -0,0 +1,15 @@
|
|||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 2 // Tag_ABI_VFP_args = 2 (Toolchain specific)
|
||||
.syntax unified
|
||||
.global f2
|
||||
.type f1, %function
|
||||
f2: bx lr
|
|
@ -0,0 +1,15 @@
|
|||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 1 // Tag_ABI_VFP_args = 1 (AAPCS, VFP variant)
|
||||
.syntax unified
|
||||
.global f1
|
||||
.type f1, %function
|
||||
f1: bx lr
|
|
@ -9,6 +9,7 @@ _start:
|
|||
bx lr
|
||||
|
||||
// CHECK: Flags [
|
||||
// CHECK-NEXT: 0x200
|
||||
// CHECK-NEXT: 0x1000000
|
||||
// CHECK-NEXT: 0x4000000
|
||||
// CHECK-NEXT: ]
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// REQUIRES:arm
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-base.s -o %tbase.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-vfp.s -o %tvfp.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-toolchain.s -o %ttoolchain.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
|
||||
// RUN: not ld.lld %t.o %tbase.o %tvfp.o 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld %t.o %tbase.o %ttoolchain.o 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld %t.o %tvfp.o %tbase.o 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld %t.o %tvfp.o %ttoolchain.o 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld %t.o %ttoolchain.o %tbase.o 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld %t.o %ttoolchain.o %tvfp.o 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: incompatible Tag_ABI_VFP_args
|
||||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 3 // Tag_ABI_VFP_args = 3 (Compatible with all)
|
||||
|
||||
.syntax unified
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start: bx lr
|
|
@ -0,0 +1,21 @@
|
|||
// REQUIRES:arm
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
|
||||
// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: arm-tag-vfp-args-illegal.s.tmp.o: unknown Tag_ABI_VFP_args value: 5
|
||||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
.eabi_attribute 28, 5 // Tag_ABI_VFP_args = 5 (Illegal value)
|
||||
|
||||
.syntax unified
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start: bx lr
|
|
@ -0,0 +1,72 @@
|
|||
// REQUIRES:arm
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-base.s -o %tbase.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-vfp.s -o %tvfp.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-toolchain.s -o %ttoolchain.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-vfp-arg-compat.s -o %tcompat.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
|
||||
|
||||
// The default for this file is 0 (Base AAPCS)
|
||||
// RUN: ld.lld %t.o -o %tdefault
|
||||
// RUN: llvm-readobj -file-headers %tdefault | FileCheck -check-prefix=CHECK-BASE %s
|
||||
|
||||
// Expect explicit Base AAPCS.
|
||||
// RUN: ld.lld %t.o %tbase.o -o %tbase
|
||||
// RUN: llvm-readobj -file-headers %tbase | FileCheck -check-prefix=CHECK-BASE %s
|
||||
|
||||
// Expect explicit Base AAPCS when linking Base and Compatible.
|
||||
// RUN: ld.lld %t.o %tbase.o %tcompat.o -o %tbasecompat
|
||||
// RUN: llvm-readobj -file-headers %tbasecompat | FileCheck -check-prefix=CHECK-BASE %s
|
||||
|
||||
// CHECK-BASE: Flags [ (0x5000200)
|
||||
// CHECK-BASE-NEXT: 0x200
|
||||
// CHECK-BASE-NEXT: 0x1000000
|
||||
// CHECK-BASE-NEXT: 0x4000000
|
||||
// CHECK-BASE-NEXT: ]
|
||||
|
||||
// Expect Hard float VFP AAPCS
|
||||
// RUN: ld.lld %t.o %tvfp.o -o %tvfp
|
||||
// RUN: llvm-readobj -file-headers %tvfp | FileCheck -check-prefix=CHECK-VFP %s
|
||||
|
||||
// Expect Hard float VFP AAPCS when linking VFP and Compatible
|
||||
// RUN: ld.lld %t.o %tvfp.o %tcompat.o -o %tvfpcompat
|
||||
// RUN: llvm-readobj -file-headers %tvfpcompat | FileCheck -check-prefix=CHECK-VFP %s
|
||||
|
||||
// CHECK-VFP: Flags [ (0x5000400)
|
||||
// CHECK-VFP-NEXT: 0x400
|
||||
// CHECK-VFP-NEXT: 0x1000000
|
||||
// CHECK-VFP-NEXT: 0x4000000
|
||||
// CHECK-VFP-NEXT: ]
|
||||
|
||||
// Expect Toolchain specifc to not use either Base or VFP AAPCS
|
||||
// RUN: ld.lld %t.o %ttoolchain.o -o %ttoolchain
|
||||
// RUN: llvm-readobj -file-headers %ttoolchain | FileCheck -check-prefix=CHECK-TOOLCHAIN %s
|
||||
|
||||
// Expect Toolchain and Compatible to have same affect as Toolchain.
|
||||
// RUN: ld.lld %t.o %ttoolchain.o %tcompat.o -o %ttoolchaincompat
|
||||
// RUN: llvm-readobj -file-headers %ttoolchaincompat | FileCheck -check-prefix=CHECK-TOOLCHAIN %s
|
||||
|
||||
// CHECK-TOOLCHAIN: Flags [ (0x5000000)
|
||||
// CHECK-TOOLCHAIN-NEXT: 0x1000000
|
||||
// CHECK-TOOLCHAIN-NEXT: 0x4000000
|
||||
// CHECK-TOOLCHAIN-NEXT: ]
|
||||
|
||||
.arch armv7-a
|
||||
.eabi_attribute 20, 1
|
||||
.eabi_attribute 21, 1
|
||||
.eabi_attribute 23, 3
|
||||
.eabi_attribute 24, 1
|
||||
.eabi_attribute 25, 1
|
||||
.eabi_attribute 26, 2
|
||||
.eabi_attribute 30, 6
|
||||
.eabi_attribute 34, 1
|
||||
.eabi_attribute 18, 4
|
||||
// We do not specify Tag_ABI_VFP_args (.eabi_attribute 28) in this file.
|
||||
// When omitted the value of the tag defaults to 0, however if there
|
||||
// are other files with explicit Tag_ABI_VFP_args we use that in
|
||||
// preference.
|
||||
|
||||
|
||||
.syntax unified
|
||||
.globl _start
|
||||
.type _start, %function
|
||||
_start: bx lr
|
Loading…
Reference in New Issue