llvm.org GIT mirror llvm / 5ee5fc4
[PowerPC] ELFv2 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 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 that 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 (via the needsRelocateWithSymbol routine). NOTE: The method used in this patch is 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 will be improved upon by a follow-on patch that modifies common code to pass the target symbol when calling needsRelocateWithSymbol. Reviewed by Hal Finkel. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213485 91177308-0d34-0410-b5e6-96231b3b80d8 Ulrich Weigand 5 years ago
9 changed file(s) with 220 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
504504 EF_PPC64_ABI = 3
505505 };
506506
507 // Special values for the st_other field in the symbol table entry for PPC64.
508 enum {
509 STO_PPC64_LOCAL_BIT = 5,
510 STO_PPC64_LOCAL_MASK = (7 << STO_PPC64_LOCAL_BIT)
511 };
512 static inline int64_t
513 decodePPC64LocalEntryOffset(unsigned Other) {
514 unsigned Val = (Other & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT;
515 return ((1 << Val) >> 2) << 2;
516 }
517 static inline unsigned
518 encodePPC64LocalEntryOffset(int64_t Offset) {
519 unsigned Val = (Offset >= 4 * 4
520 ? (Offset >= 8 * 4
521 ? (Offset >= 16 * 4 ? 6 : 5)
522 : 4)
523 : (Offset >= 2 * 4
524 ? 3
525 : (Offset >= 1 * 4 ? 2 : 0)));
526 return Val << STO_PPC64_LOCAL_BIT;
527 }
528
507529 // ELF Relocation types for PPC64
508530 enum {
509531 R_PPC64_NONE = 0,
1414 #include "llvm/ADT/SmallVector.h"
1515 #include "llvm/ADT/StringSwitch.h"
1616 #include "llvm/ADT/Twine.h"
17 #include "llvm/MC/MCContext.h"
1718 #include "llvm/MC/MCExpr.h"
1819 #include "llvm/MC/MCInst.h"
1920 #include "llvm/MC/MCInstrInfo.h"
244245 bool ParseDirectiveMachine(SMLoc L);
245246 bool ParseDarwinDirectiveMachine(SMLoc L);
246247 bool ParseDirectiveAbiVersion(SMLoc L);
248 bool ParseDirectiveLocalEntry(SMLoc L);
247249
248250 bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
249251 OperandVector &Operands, MCStreamer &Out,
14141416 return ParseDirectiveMachine(DirectiveID.getLoc());
14151417 if (IDVal == ".abiversion")
14161418 return ParseDirectiveAbiVersion(DirectiveID.getLoc());
1419 if (IDVal == ".localentry")
1420 return ParseDirectiveLocalEntry(DirectiveID.getLoc());
14171421 } else {
14181422 if (IDVal == ".machine")
14191423 return ParseDarwinDirectiveMachine(DirectiveID.getLoc());
15561560
15571561 return false;
15581562 }
1563
1564 /// ParseDirectiveLocalEntry
1565 /// ::= .localentry symbol, expression
1566 bool PPCAsmParser::ParseDirectiveLocalEntry(SMLoc L) {
1567 StringRef Name;
1568 if (getParser().parseIdentifier(Name)) {
1569 Error(L, "expected identifier in directive");
1570 return false;
1571 }
1572 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
1573
1574 if (getLexer().isNot(AsmToken::Comma)) {
1575 Error(L, "unexpected token in directive");
1576 return false;
1577 }
1578 Lex();
1579
1580 const MCExpr *Expr;
1581 if (getParser().parseExpression(Expr)) {
1582 Error(L, "expected expression");
1583 return false;
1584 }
1585
1586 if (getLexer().isNot(AsmToken::EndOfStatement)) {
1587 Error(L, "unexpected token in directive");
1588 return false;
1589 }
1590
1591 PPCTargetStreamer &TStreamer =
1592 *static_cast(
1593 getParser().getStreamer().getTargetStreamer());
1594 TStreamer.emitLocalEntry(Sym, Expr);
1595
1596 return false;
1597 }
1598
1599
15591600
15601601 /// Force static initialization.
15611602 extern "C" void LLVMInitializePowerPCAsmParser() {
88
99 #include "MCTargetDesc/PPCMCTargetDesc.h"
1010 #include "MCTargetDesc/PPCFixupKinds.h"
11 #include "llvm/MC/MCAssembler.h"
1112 #include "llvm/MC/MCAsmBackend.h"
13 #include "llvm/MC/MCELF.h"
1214 #include "llvm/MC/MCELFObjectWriter.h"
1315 #include "llvm/MC/MCFixupKindInfo.h"
1416 #include "llvm/MC/MCMachObjectWriter.h"
127129 }
128130 }
129131
132 void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
133 const MCFixup &Fixup, const MCFragment *DF,
134 const MCValue &Target, uint64_t &Value,
135 bool &IsResolved) override {
136 switch ((PPC::Fixups)Fixup.getKind()) {
137 default: break;
138 case PPC::fixup_ppc_br24:
139 case PPC::fixup_ppc_br24abs:
140 // If the target symbol has a local entry point we must not attempt
141 // to resolve the fixup directly. Emit a relocation and leave
142 // resolution of the final target address to the linker.
143 if (const MCSymbolRefExpr *A = Target.getSymA()) {
144 const MCSymbolData &Data = Asm.getSymbolData(A->getSymbol());
145 // The "other" values are stored in the last 6 bits of the second byte.
146 // The traditional defines for STO values assume the full byte and thus
147 // the shift to pack it.
148 unsigned Other = MCELF::getOther(Data) << 2;
149 if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)
150 IsResolved = false;
151 }
152 break;
153 }
154 }
155
130156 bool mayNeedRelaxation(const MCInst &Inst) const override {
131157 // FIXME.
132158 return false;
2929 bool IsPCRel) const;
3030 unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
3131 bool IsPCRel) const override;
32
33 bool needsRelocateWithSymbol(unsigned Type) const override;
3234 };
3335 }
3436
386388 return getRelocTypeInner(Target, Fixup, IsPCRel);
387389 }
388390
391 bool PPCELFObjectWriter::needsRelocateWithSymbol(unsigned Type) const {
392 switch (Type) {
393 default:
394 return false;
395
396 case ELF::R_PPC_REL24:
397 // FIXME: We only need to keep the target symbol of the relocation
398 // if the symbol uses a local entry point. Unfortunately, we do not
399 // have access to the symbol here ...
400 return true;
401 }
402 }
403
389404 MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS,
390405 bool Is64Bit,
391406 bool IsLittleEndian,
1515 #include "PPCMCAsmInfo.h"
1616 #include "PPCTargetStreamer.h"
1717 #include "llvm/MC/MCCodeGenInfo.h"
18 #include "llvm/MC/MCELF.h"
1819 #include "llvm/MC/MCELFStreamer.h"
20 #include "llvm/MC/MCExpr.h"
1921 #include "llvm/MC/MCInstrInfo.h"
2022 #include "llvm/MC/MCRegisterInfo.h"
2123 #include "llvm/MC/MCStreamer.h"
129131 virtual void emitAbiVersion(int AbiVersion) override {
130132 OS << "\t.abiversion " << AbiVersion << '\n';
131133 }
134 virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) {
135 OS << "\t.localentry\t" << *S << ", " << *LocalOffset << '\n';
136 }
132137 };
133138
134139 class PPCTargetELFStreamer : public PPCTargetStreamer {
152157 Flags |= (AbiVersion & ELF::EF_PPC64_ABI);
153158 MCA.setELFHeaderEFlags(Flags);
154159 }
160 virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) {
161 MCAssembler &MCA = getStreamer().getAssembler();
162 MCSymbolData &Data = getStreamer().getOrCreateSymbolData(S);
163
164 int64_t Res;
165 if (!LocalOffset->EvaluateAsAbsolute(Res, MCA))
166 report_fatal_error(".localentry expression must be absolute.");
167
168 unsigned Encoded = ELF::encodePPC64LocalEntryOffset(Res);
169 if (Res != ELF::decodePPC64LocalEntryOffset(Encoded))
170 report_fatal_error(".localentry expression cannot be encoded.");
171
172 // The "other" values are stored in the last 6 bits of the second byte.
173 // The traditional defines for STO values assume the full byte and thus
174 // the shift to pack it.
175 unsigned Other = MCELF::getOther(Data) << 2;
176 Other &= ~ELF::STO_PPC64_LOCAL_MASK;
177 Other |= Encoded;
178 MCELF::setOther(Data, Other >> 2);
179
180 // For GAS compatibility, unless we already saw a .abiversion directive,
181 // set e_flags to indicate ELFv2 ABI.
182 unsigned Flags = MCA.getELFHeaderEFlags();
183 if ((Flags & ELF::EF_PPC64_ABI) == 0)
184 MCA.setELFHeaderEFlags(Flags | 2);
185 }
155186 };
156187
157188 class PPCTargetMachOStreamer : public PPCTargetStreamer {
166197 }
167198 virtual void emitAbiVersion(int AbiVersion) override {
168199 llvm_unreachable("Unknown pseudo-op: .abiversion");
200 }
201 virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) {
202 llvm_unreachable("Unknown pseudo-op: .localentry");
169203 }
170204 };
171205 }
1919 virtual void emitTCEntry(const MCSymbol &S) = 0;
2020 virtual void emitMachine(StringRef CPU) = 0;
2121 virtual void emitAbiVersion(int AbiVersion) = 0;
22 virtual void emitLocalEntry(MCSymbol *S, const MCExpr *LocalOffset) = 0;
2223 };
2324 }
2425
0
1 # RUN: not llvm-mc -triple powerpc64-unknown-unknown -filetype=obj < %s 2> %t
2 # RUN: FileCheck < %t %s
3 # RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj < %s 2> %t
4 # RUN: FileCheck < %t %s
5
6 sym:
7 .localentry sym, 123
8
9 # CHECK: LLVM ERROR: .localentry expression cannot be encoded.
10
0
1 # RUN: not llvm-mc -triple powerpc64-unknown-unknown -filetype=obj < %s 2> %t
2 # RUN: FileCheck < %t %s
3 # RUN: not llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj < %s 2> %t
4 # RUN: FileCheck < %t %s
5
6 .globl remote_sym
7 sym:
8 .localentry sym, remote_sym
9
10 # CHECK: LLVM ERROR: .localentry expression must be absolute.
11
0
1 # RUN: llvm-mc -triple powerpc64-unknown-unknown -filetype=obj %s | \
2 # RUN: llvm-readobj -h -r -symbols | FileCheck %s
3 # RUN: llvm-mc -triple powerpc64le-unknown-unknown -filetype=obj %s | \
4 # RUN: llvm-readobj -h -r -symbols | FileCheck %s
5
6 .type callee1, @function
7 callee1:
8 nop
9 nop
10 .localentry callee1, .-callee1
11 nop
12 nop
13 .size callee1, .-callee1
14
15 .type callee2, @function
16 callee2:
17 nop
18 nop
19 .size callee2, .-callee2
20
21 .type caller, @function
22 caller:
23 bl callee1
24 nop
25 bl callee2
26 nop
27 .size caller, .-caller
28
29 # Verify that use of .localentry implies ABI version 2
30 # CHECK: ElfHeader {
31 # CHECK: Flags [ (0x2)
32
33 # Verify that fixups to local function symbols are performed only
34 # if the target symbol does not use .localentry
35 # CHECK: Relocations [
36 # CHECK: Section ({{[0-9]*}}) .rela.text {
37 # CHECK-NEXT: R_PPC64_REL24 callee1
38 # CHECK-NEXT: }
39 # CHECK-NOT: R_PPC64_REL24 callee2
40
41 # Verify that .localentry is encoded in the Other field.
42 # CHECK: Symbols [
43 # CHECK: Name: callee1
44 # CHECK-NEXT: Value:
45 # CHECK-NEXT: Size: 16
46 # CHECK-NEXT: Binding: Local
47 # CHECK-NEXT: Type: Function
48 # CHECK-NEXT: Other: 96
49 # CHECK-NEXT: Section: .text
50 # CHECK: Name: callee2
51 # CHECK-NEXT: Value:
52 # CHECK-NEXT: Size: 8
53 # CHECK-NEXT: Binding: Local
54 # CHECK-NEXT: Type: Function
55 # CHECK-NEXT: Other: 0
56 # CHECK-NEXT: Section: .text
57