Summary: A R_REF relocation as a non-relocating reference is required to prevent garbage collection (by the binder) of the ref symbol in object generation.
Reviewed By: shchenz
Differential Revision: https://reviews.llvm.org/D144356
/// relocation table for one or more symbols.
///
/// \param Sym - The symbol on the .ref directive.
- virtual void emitXCOFFRefDirective(StringRef Sym);
+ virtual void emitXCOFFRefDirective(const MCSymbol *Symbol);
/// Emit an ELF .size directive.
///
void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
MCSymbolAttr Linkage,
MCSymbolAttr Visibility) override;
- void emitXCOFFRefDirective(StringRef Name) override {
- report_fatal_error("emitXCOFFRefDirective is not implemented yet on object"
- "generation path");
- }
+ void emitXCOFFRefDirective(const MCSymbol *Symbol) override;
void emitXCOFFRenameDirective(const MCSymbol *Name,
StringRef Rename) override {
report_fatal_error("emitXCOFFRenameDirective is not implemented yet on "
void emitXCOFFRenameDirective(const MCSymbol *Name,
StringRef Rename) override;
- void emitXCOFFRefDirective(StringRef Name) override;
+ void emitXCOFFRefDirective(const MCSymbol *Symbol) override;
void emitXCOFFExceptDirective(const MCSymbol *Symbol,
const MCSymbol *Trap,
EmitEOL();
}
-void MCAsmStreamer::emitXCOFFRefDirective(StringRef Name) {
- OS << "\t.ref " << Name;
+void MCAsmStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
+ OS << "\t.ref ";
+ Symbol->print(OS, MAI);
EmitEOL();
}
"XCOFF targets");
}
-void MCStreamer::emitXCOFFRefDirective(StringRef Name) {
+void MCStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
llvm_unreachable("emitXCOFFRefDirective is only supported on XCOFF targets");
}
emitSymbolAttribute(Symbol, Visibility);
}
+void MCXCOFFStreamer::emitXCOFFRefDirective(const MCSymbol *Symbol) {
+ // Add a Fixup here to later record a relocation of type R_REF to prevent the
+ // ref symbol from being garbage collected (by the binder).
+ MCDataFragment *DF = getOrCreateDataFragment();
+ const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
+ std::optional<MCFixupKind> MaybeKind =
+ getAssembler().getBackend().getFixupKind("R_REF");
+ if (!MaybeKind)
+ report_fatal_error("failed to get fixup kind for R_REF relocation");
+
+ MCFixupKind Kind = *MaybeKind;
+ MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, Kind);
+ DF->getFixups().push_back(Fixup);
+}
+
void MCXCOFFStreamer::emitXCOFFExceptDirective(const MCSymbol *Symbol,
const MCSymbol *Trap,
unsigned Lang, unsigned Reason,
// instr address plus any constant value.
FixedValue =
SectionMap[SymASec]->Address - BRInstrAddress + Target.getConstant();
- }
+ } else if (Type == XCOFF::RelocationType::R_REF)
+ // The FixedValue should always be 0 since it specifies a nonrelocating
+ // reference.
+ FixedValue = 0;
assert((Fixup.getOffset() <=
MaxRawDataSize - Layout.getFragmentOffset(Fragment)) &&
createObjectTargetWriter() const override {
return createPPCXCOFFObjectWriter(TT.isArch64Bit());
}
+
+ std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
};
} // end anonymous namespace
return std::nullopt;
}
+std::optional<MCFixupKind>
+XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {
+ return StringSwitch<std::optional<MCFixupKind>>(Name)
+ .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)
+ .Default(std::nullopt);
+}
+
MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
/// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the
/// TLS general and local dynamic models, or inserts the thread-pointer
- /// register number.
+ /// register number. It can also be used to tie the ref symbol to prevent it
+ /// from being garbage collected on AIX.
fixup_ppc_nofixup,
/// A 16-bit fixup corresponding to lo16(_foo) with implied 3 zero bits for
return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25};
case PPC::fixup_ppc_br24abs:
return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25};
+ case PPC::fixup_ppc_nofixup: {
+ if (Modifier == MCSymbolRefExpr::VK_None)
+ return {XCOFF::RelocationType::R_REF, 0};
+ else
+ llvm_unreachable("Unsupported Modifier");
+ } break;
case FK_Data_4:
case FK_Data_8:
const uint8_t SignAndSizeForFKData =
OutStreamer->switchSection(CntsSection);
if (OutContext.hasXCOFFSection(
"__llvm_prf_data",
- XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD)))
- OutStreamer->emitXCOFFRefDirective("__llvm_prf_data[RW]");
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) {
+ MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_data[RW]");
+ OutStreamer->emitXCOFFRefDirective(S);
+ }
if (OutContext.hasXCOFFSection(
"__llvm_prf_names",
- XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD)))
- OutStreamer->emitXCOFFRefDirective("__llvm_prf_names[RO]");
+ XCOFF::CsectProperties(XCOFF::XMC_RO, XCOFF::XTY_SD))) {
+ MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_names[RO]");
+ OutStreamer->emitXCOFFRefDirective(S);
+ }
if (OutContext.hasXCOFFSection(
"__llvm_prf_vnds",
- XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD)))
- OutStreamer->emitXCOFFRefDirective("__llvm_prf_vnds[RW]");
+ XCOFF::CsectProperties(XCOFF::XMC_RW, XCOFF::XTY_SD))) {
+ MCSymbol *S = OutContext.getOrCreateSymbol("__llvm_prf_vnds[RW]");
+ OutStreamer->emitXCOFFRefDirective(S);
+ }
}
}
; RUN: rm -rf %t && split-file %s %t
-; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/no-ref.ll | FileCheck %s --check-prefixes=NOREF
-; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/no-vnds.ll | FileCheck %s --check-prefixes=NOVNDS
-; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff -xcoff-traceback-table=false < %t/with-vnds.ll | FileCheck %s --check-prefixes=WITHVNDS
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false < %t/no-ref.ll | FileCheck %s --check-prefixes=NOREF
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false --filetype=obj < %t/no-ref.ll -o %t/no-ref.o
+; RUN: llvm-objdump %t/no-ref.o -r | FileCheck %s --check-prefix=NOREF-OBJ
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false < %t/no-vnds.ll | FileCheck %s --check-prefixes=NOVNDS
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false --filetype=obj < %t/no-vnds.ll -o %t/no-vnds.o
+; RUN: llvm-objdump %t/no-vnds.o -r | FileCheck %s --check-prefix=NOVNDS-OBJ
+
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false < %t/with-vnds.ll | FileCheck %s --check-prefixes=WITHVNDS
+; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mattr=-altivec -mtriple powerpc-ibm-aix-xcoff \
+; RUN: -xcoff-traceback-table=false --filetype=obj < %t/with-vnds.ll -o %t/with-vnds.o
+; RUN: llvm-objdump %t/with-vnds.o -tr | FileCheck %s --check-prefix=WITHVNDS-OBJ
;--- no-ref.ll
; The absence of a __llvm_prf_cnts section should stop generating the .refs.
; NOREF-NOT: .ref __llvm_prf_names
; NOREF-NOT: .ref __llvm_prf_vnds
+; NOREF-OBJ-NOT: R_REF __llvm_prf_data
+; NOREF-OBJ-NOT: R_REF __llvm_prf_names
+; NOREF-OBJ-NOT: R_REF __llvm_prf_vnds
+
;--- no-vnds.ll
; This is the most common case. When -fprofile-generate is used and there exists executable code, we generate the __llvm_prf_cnts, __llvm_prf_data, and __llvm_prf_names sections.
;
; NOVNDS-NEXT: .ref __llvm_prf_names[RO]
; NOVNDS-NOT: .ref __llvm_prf_vnds
+; NOVNDS-OBJ: 00000008 R_REF __llvm_prf_data
+; NOVNDS-OBJ: 00000008 R_REF __llvm_prf_names
+; NOVNDS-OBJ-NOT: R_REF __llvm_prf_vnds
+
;--- with-vnds.ll
; When value profiling is needed, the PGO instrumentation generates variables in the __llvm_prf_vnds section, so we generate a .ref for them too.
;
; WITHVNDS-NEXT: .ref __llvm_prf_data[RW]
; WITHVNDS-NEXT: .ref __llvm_prf_names[RO]
; WITHVNDS-NEXT: .ref __llvm_prf_vnds[RW]
+
+; WITHVNDS-OBJ: SYMBOL TABLE:
+; WITHVNDS-OBJ-NEXT: 00000000 df *DEBUG* 00000000 <stdin>
+; WITHVNDS-OBJ-NEXT: 00000000 l .text 00000008 .text
+; WITHVNDS-OBJ-NEXT: 00000000 g F .text (csect: .text) 00000000 .main
+; WITHVNDS-OBJ-NEXT: 00000008 l .text 00000006 __llvm_prf_names
+; WITHVNDS-OBJ-NEXT: 00000010 l O .data 00000008 __llvm_prf_cnts
+; WITHVNDS-OBJ-NEXT: 00000018 l O .data 00000008 __llvm_prf_data
+; WITHVNDS-OBJ-NEXT: 00000020 l O .data 000000f0 __llvm_prf_vnds
+; WITHVNDS-OBJ-NEXT: 00000110 g O .data 0000000c main
+; WITHVNDS-OBJ-NEXT: 0000011c l .data 00000000 TOC
+
+; WITHVNDS-OBJ: RELOCATION RECORDS FOR [.data]:
+; WITHVNDS-OBJ-NEXT: OFFSET TYPE VALUE
+; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_data
+; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_names
+; WITHVNDS-OBJ-NEXT: 00000008 R_REF __llvm_prf_vnds
+; WITHVNDS-OBJ-NEXT: 00000100 R_POS .main
+; WITHVNDS-OBJ-NEXT: 00000104 R_POS TOC