Skip to content

Commit 8331aae

Browse files
committed
[ARM] Add support for embedded position-independent code
This patch adds support for some new relocation models to the ARM backend: * Read-only position independence (ROPI): Code and read-only data is accessed PC-relative. The offsets between all code and RO data sections are known at static link time. This does not affect read-write data. * Read-write position independence (RWPI): Read-write data is accessed relative to the static base register (r9). The offsets between all writeable data sections are known at static link time. This does not affect read-only data. These two modes are independent (they specify how different objects should be addressed), so they can be used individually or together. They are otherwise the same as the "static" relocation model, and are not compatible with SysV-style PIC using a global offset table. These modes are normally used by bare-metal systems or systems with small real-time operating systems. They are designed to avoid the need for a dynamic linker, the only initialisation required is setting r9 to an appropriate value for RWPI code. I have only added support to SelectionDAG, not FastISel, because FastISel is currently disabled for bare-metal targets where these modes would be used. Differential Revision: https://reviews.llvm.org/D23195 llvm-svn: 278015
1 parent 219feac commit 8331aae

16 files changed

+551
-21
lines changed

llvm/include/llvm/CodeGen/CommandFlags.h

+6
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ cl::opt<Reloc::Model> RelocModel(
5454
"Fully relocatable, position independent code"),
5555
clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
5656
"Relocatable external references, non-relocatable code"),
57+
clEnumValN(Reloc::ROPI, "ropi",
58+
"Code and read-only data relocatable, accessed PC-relative"),
59+
clEnumValN(Reloc::RWPI, "rwpi",
60+
"Read-write data relocatable, accessed relative to static base"),
61+
clEnumValN(Reloc::ROPI_RWPI, "ropi-rwpi",
62+
"Combination of ropi and rwpi"),
5763
clEnumValEnd));
5864

5965
static inline Optional<Reloc::Model> getRelocModel() {

llvm/include/llvm/Support/CodeGen.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace llvm {
1919

2020
// Relocation model types.
2121
namespace Reloc {
22-
enum Model { Static, PIC_, DynamicNoPIC };
22+
enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI };
2323
}
2424

2525
// Code model types.

llvm/lib/Target/ARM/ARMAsmPrinter.cpp

+25-10
Original file line numberDiff line numberDiff line change
@@ -725,16 +725,27 @@ void ARMAsmPrinter::emitAttributes() {
725725
ATS.emitFPU(ARM::FK_VFPV2);
726726
}
727727

728+
// RW data addressing.
728729
if (isPositionIndependent()) {
729-
// PIC specific attributes.
730730
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
731731
ARMBuildAttrs::AddressRWPCRel);
732+
} else if (STI.isRWPI()) {
733+
// RWPI specific attributes.
734+
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
735+
ARMBuildAttrs::AddressRWSBRel);
736+
}
737+
738+
// RO data addressing.
739+
if (isPositionIndependent() || STI.isROPI()) {
732740
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RO_data,
733741
ARMBuildAttrs::AddressROPCRel);
742+
}
743+
744+
// GOT use.
745+
if (isPositionIndependent()) {
734746
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
735747
ARMBuildAttrs::AddressGOT);
736748
} else {
737-
// Allow direct addressing of imported data for all other relocation models.
738749
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
739750
ARMBuildAttrs::AddressDirect);
740751
}
@@ -858,14 +869,16 @@ void ARMAsmPrinter::emitAttributes() {
858869
}
859870
}
860871

861-
// TODO: We currently only support either reserving the register, or treating
862-
// it as another callee-saved register, but not as SB or a TLS pointer; It
863-
// would instead be nicer to push this from the frontend as metadata, as we do
864-
// for the wchar and enum size tags
865-
if (STI.isR9Reserved())
866-
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9Reserved);
872+
// We currently do not support using R9 as the TLS pointer.
873+
if (STI.isRWPI())
874+
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
875+
ARMBuildAttrs::R9IsSB);
876+
else if (STI.isR9Reserved())
877+
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
878+
ARMBuildAttrs::R9Reserved);
867879
else
868-
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9IsGPR);
880+
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
881+
ARMBuildAttrs::R9IsGPR);
869882

870883
if (STI.hasTrustZone() && STI.hasVirtualization())
871884
ATS.emitAttribute(ARMBuildAttrs::Virtualization_use,
@@ -899,6 +912,8 @@ getModifierVariantKind(ARMCP::ARMCPModifier Modifier) {
899912
return MCSymbolRefExpr::VK_TPOFF;
900913
case ARMCP::GOTTPOFF:
901914
return MCSymbolRefExpr::VK_GOTTPOFF;
915+
case ARMCP::SBREL:
916+
return MCSymbolRefExpr::VK_ARM_SBREL;
902917
case ARMCP::GOT_PREL:
903918
return MCSymbolRefExpr::VK_ARM_GOT_PREL;
904919
case ARMCP::SECREL:
@@ -1037,7 +1052,7 @@ void ARMAsmPrinter::EmitJumpTableAddrs(const MachineInstr *MI) {
10371052
// .word (LBB1 - LJTI_0_0)
10381053
const MCExpr *Expr = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
10391054

1040-
if (isPositionIndependent())
1055+
if (isPositionIndependent() || Subtarget->isROPI())
10411056
Expr = MCBinaryExpr::createSub(Expr, MCSymbolRefExpr::create(JTISymbol,
10421057
OutContext),
10431058
OutContext);

llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -4119,6 +4119,9 @@ bool ARMBaseInstrInfo::verifyInstruction(const MachineInstr &MI,
41194119
void ARMBaseInstrInfo::expandLoadStackGuardBase(MachineBasicBlock::iterator MI,
41204120
unsigned LoadImmOpc,
41214121
unsigned LoadOpc) const {
4122+
assert(!Subtarget.isROPI() && !Subtarget.isRWPI() &&
4123+
"ROPI/RWPI not currently supported with stack guard");
4124+
41224125
MachineBasicBlock &MBB = *MI->getParent();
41234126
DebugLoc DL = MI->getDebugLoc();
41244127
unsigned Reg = MI->getOperand(0).getReg();

llvm/lib/Target/ARM/ARMConstantPoolValue.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ const char *ARMConstantPoolValue::getModifierText() const {
6060
return "gottpoff";
6161
case ARMCP::TPOFF:
6262
return "tpoff";
63+
case ARMCP::SBREL:
64+
return "SBREL";
6365
case ARMCP::SECREL:
6466
return "secrel32";
6567
}

llvm/lib/Target/ARM/ARMConstantPoolValue.h

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace ARMCP {
4343
GOTTPOFF, /// Global Offset Table, Thread Pointer Offset
4444
TPOFF, /// Thread Pointer Offset
4545
SECREL, /// Section Relative (Windows TLS)
46+
SBREL, /// Static Base Relative (RWPI)
4647
};
4748
}
4849

llvm/lib/Target/ARM/ARMFastISel.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,10 @@ unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, MVT VT) {
546546
// For now 32-bit only.
547547
if (VT != MVT::i32 || GV->isThreadLocal()) return 0;
548548

549+
// ROPI/RWPI not currently supported.
550+
if (Subtarget->isROPI() || Subtarget->isRWPI())
551+
return 0;
552+
549553
bool IsIndirect = Subtarget->isGVIndirectSymbol(GV);
550554
const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass
551555
: &ARM::GPRRegClass;

llvm/lib/Target/ARM/ARMISelLowering.cpp

+30-2
Original file line numberDiff line numberDiff line change
@@ -2530,7 +2530,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op,
25302530
EVT PtrVT = getPointerTy(DAG.getDataLayout());
25312531
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
25322532
SDValue CPAddr;
2533-
bool IsPositionIndependent = isPositionIndependent();
2533+
bool IsPositionIndependent = isPositionIndependent() || Subtarget->isROPI();
25342534
if (!IsPositionIndependent) {
25352535
CPAddr = DAG.getTargetConstantPool(BA, PtrVT, 4);
25362536
} else {
@@ -2800,6 +2800,11 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
28002800
SDLoc dl(Op);
28012801
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
28022802
const TargetMachine &TM = getTargetMachine();
2803+
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
2804+
GV = GA->getBaseObject();
2805+
bool IsRO =
2806+
(isa<GlobalVariable>(GV) && cast<GlobalVariable>(GV)->isConstant()) ||
2807+
isa<Function>(GV);
28032808
if (isPositionIndependent()) {
28042809
bool UseGOT_PREL = !TM.shouldAssumeDSOLocal(*GV->getParent(), GV);
28052810

@@ -2826,6 +2831,23 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
28262831
DAG.getLoad(PtrVT, dl, Chain, Result,
28272832
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
28282833
return Result;
2834+
} else if (Subtarget->isROPI() && IsRO) {
2835+
// PC-relative.
2836+
SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT);
2837+
SDValue Result = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVT, G);
2838+
return Result;
2839+
} else if (Subtarget->isRWPI() && !IsRO) {
2840+
// SB-relative.
2841+
ARMConstantPoolValue *CPV =
2842+
ARMConstantPoolConstant::Create(GV, ARMCP::SBREL);
2843+
SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4);
2844+
CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
2845+
SDValue G = DAG.getLoad(
2846+
PtrVT, dl, DAG.getEntryNode(), CPAddr,
2847+
MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
2848+
SDValue SB = DAG.getCopyFromReg(DAG.getEntryNode(), dl, ARM::R9, PtrVT);
2849+
SDValue Result = DAG.getNode(ISD::ADD, dl, PtrVT, SB, G);
2850+
return Result;
28292851
}
28302852

28312853
// If we have T2 ops, we can materialize the address directly via movt/movw
@@ -2847,6 +2869,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
28472869

28482870
SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op,
28492871
SelectionDAG &DAG) const {
2872+
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
2873+
"ROPI/RWPI not currently supported for Darwin");
28502874
EVT PtrVT = getPointerTy(DAG.getDataLayout());
28512875
SDLoc dl(Op);
28522876
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
@@ -2873,6 +2897,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op,
28732897
assert(Subtarget->isTargetWindows() && "non-Windows COFF is not supported");
28742898
assert(Subtarget->useMovt(DAG.getMachineFunction()) &&
28752899
"Windows on ARM expects to use movw/movt");
2900+
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
2901+
"ROPI/RWPI not currently supported for Windows");
28762902

28772903
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
28782904
const ARMII::TOF TargetFlags =
@@ -4123,7 +4149,7 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
41234149
return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain,
41244150
Addr, Op.getOperand(2), JTI);
41254151
}
4126-
if (isPositionIndependent()) {
4152+
if (isPositionIndependent() || Subtarget->isROPI()) {
41274153
Addr =
41284154
DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr,
41294155
MachinePointerInfo::getJumpTable(DAG.getMachineFunction()));
@@ -7271,6 +7297,8 @@ void ARMTargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI,
72717297
MachineBasicBlock *MBB,
72727298
MachineBasicBlock *DispatchBB,
72737299
int FI) const {
7300+
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
7301+
"ROPI/RWPI not currently supported with SjLj");
72747302
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
72757303
DebugLoc dl = MI.getDebugLoc();
72767304
MachineFunction *MF = MBB->getParent();

llvm/lib/Target/ARM/ARMSubtarget.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
199199
(Options.UnsafeFPMath || isTargetDarwin()))
200200
UseNEONForSinglePrecisionFP = true;
201201

202+
if (isRWPI())
203+
ReserveR9 = true;
204+
202205
// FIXME: Teach TableGen to deal with these instead of doing it manually here.
203206
switch (ARMProcFamily) {
204207
case Others:
@@ -261,6 +264,15 @@ bool ARMSubtarget::isAAPCS16_ABI() const {
261264
return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16;
262265
}
263266

267+
bool ARMSubtarget::isROPI() const {
268+
return TM.getRelocationModel() == Reloc::ROPI ||
269+
TM.getRelocationModel() == Reloc::ROPI_RWPI;
270+
}
271+
bool ARMSubtarget::isRWPI() const {
272+
return TM.getRelocationModel() == Reloc::RWPI ||
273+
TM.getRelocationModel() == Reloc::ROPI_RWPI;
274+
}
275+
264276
bool ARMSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
265277
if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
266278
return true;

llvm/lib/Target/ARM/ARMSubtarget.h

+3
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,9 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
544544
bool isAAPCS_ABI() const;
545545
bool isAAPCS16_ABI() const;
546546

547+
bool isROPI() const;
548+
bool isRWPI() const;
549+
547550
bool useSoftFloat() const { return UseSoftFloat; }
548551
bool isThumb() const { return InThumbMode; }
549552
bool isThumb1Only() const { return InThumbMode && !HasThumb2; }

llvm/lib/Target/ARM/ARMTargetMachine.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ static Reloc::Model getEffectiveRelocModel(const Triple &TT,
184184
// Default relocation model on Darwin is PIC.
185185
return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static;
186186

187+
if (*RM == Reloc::ROPI || *RM == Reloc::RWPI || *RM == Reloc::ROPI_RWPI)
188+
assert(TT.isOSBinFormatELF() &&
189+
"ROPI/RWPI currently only supported for ELF");
190+
187191
// DynamicNoPIC is only used on darwin.
188192
if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin())
189193
return Reloc::Static;

llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp

+18-2
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,26 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
242242
Type = ELF::R_ARM_JUMP24;
243243
break;
244244
case ARM::fixup_arm_movt_hi16:
245-
Type = ELF::R_ARM_MOVT_ABS;
245+
switch (Modifier) {
246+
default: llvm_unreachable("Unsupported Modifier");
247+
case MCSymbolRefExpr::VK_None:
248+
Type = ELF::R_ARM_MOVT_ABS;
249+
break;
250+
case MCSymbolRefExpr::VK_ARM_SBREL:
251+
Type = ELF:: R_ARM_MOVT_BREL;
252+
break;
253+
}
246254
break;
247255
case ARM::fixup_arm_movw_lo16:
248-
Type = ELF::R_ARM_MOVW_ABS_NC;
256+
switch (Modifier) {
257+
default: llvm_unreachable("Unsupported Modifier");
258+
case MCSymbolRefExpr::VK_None:
259+
Type = ELF::R_ARM_MOVW_ABS_NC;
260+
break;
261+
case MCSymbolRefExpr::VK_ARM_SBREL:
262+
Type = ELF:: R_ARM_MOVW_BREL_NC;
263+
break;
264+
}
249265
break;
250266
case ARM::fixup_t2_movt_hi16:
251267
Type = ELF::R_ARM_THM_MOVT_ABS;

llvm/lib/Target/TargetLoweringObjectFile.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,13 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
208208
}
209209

210210
} else {
211-
// In static relocation model, the linker will resolve all addresses, so
212-
// the relocation entries will actually be constants by the time the app
213-
// starts up. However, we can't put this into a mergable section, because
214-
// the linker doesn't take relocations into consideration when it tries to
215-
// merge entries in the section.
216-
if (ReloModel == Reloc::Static)
211+
// In static, ROPI and RWPI relocation models, the linker will resolve
212+
// all addresses, so the relocation entries will actually be constants by
213+
// the time the app starts up. However, we can't put this into a
214+
// mergable section, because the linker doesn't take relocations into
215+
// consideration when it tries to merge entries in the section.
216+
if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI ||
217+
ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI)
217218
return SectionKind::getReadOnly();
218219

219220
// Otherwise, the dynamic linker needs to fix it up, put it in the

0 commit comments

Comments
 (0)