static bool isLocal(const MCSymbolData &Data, bool isUsedInReloc);
static bool IsELFMetaDataSection(const MCSectionData &SD);
static uint64_t DataSectionSize(const MCSectionData &SD);
- static uint64_t GetSectionFileSize(const MCAsmLayout &Layout,
- const MCSectionData &SD);
static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout,
const MCSectionData &SD);
- void WriteDataSectionData(MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCSectionELF &Section);
+ void writeDataSectionData(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCSectionData &SD);
/// Helper struct for containing some precomputed information on symbols.
struct ELFSymbolData {
}
void WriteHeader(const MCAssembler &Asm,
- uint64_t SectionHeaderOffset,
unsigned NumberOfSections);
void WriteSymbol(SymbolTableWriter &Writer, ELFSymbolData &MSD,
void ExecutePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) override;
- void writeSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap,
+ void writeSectionHeader(ArrayRef<const MCSectionELF *> Sections,
+ MCAssembler &Asm, const GroupMapTy &GroupMap,
const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetMapTy &SectionOffsetMap);
- void ComputeSectionOrder(MCAssembler &Asm,
- std::vector<const MCSectionELF*> &Sections);
-
void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
uint64_t Address, uint64_t Offset,
uint64_t Size, uint32_t Link, uint32_t Info,
bool
IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
const MCSymbolData &DataA,
- const MCSymbolData *DataB,
const MCFragment &FB,
bool InSet,
bool IsPCRel) const override;
// Emit the ELF header.
void ELFObjectWriter::WriteHeader(const MCAssembler &Asm,
- uint64_t SectionHeaderOffset,
unsigned NumberOfSections) {
// ELF Header
// ----------
// emitWord method behaves differently for ELF32 and ELF64, writing
// 4 bytes in the former and 8 in the latter.
- Write8(0x7f); // e_ident[EI_MAG0]
- Write8('E'); // e_ident[EI_MAG1]
- Write8('L'); // e_ident[EI_MAG2]
- Write8('F'); // e_ident[EI_MAG3]
+ WriteBytes(ELF::ElfMagic); // e_ident[EI_MAG0] to e_ident[EI_MAG3]
Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS]
Write32(ELF::EV_CURRENT); // e_version
WriteWord(0); // e_entry, no entry point in .o file
WriteWord(0); // e_phoff, no program header for .o
- WriteWord(SectionHeaderOffset); // e_shoff = sec hdr table off in bytes
+ WriteWord(0); // e_shoff = sec hdr table off in bytes
// e_flags = whatever the target wants
Write32(Asm.getELFHeaderEFlags());
return nullptr;
}
+// True if the assembler knows nothing about the final value of the symbol.
+// This doesn't cover the comdat issues, since in those cases the assembler
+// can at least know that all symbols in the section will move together.
static bool isWeak(const MCSymbolData &D) {
- return D.getFlags() & ELF_STB_Weak || MCELF::GetType(D) == ELF::STT_GNU_IFUNC;
+ if (MCELF::GetType(D) == ELF::STT_GNU_IFUNC)
+ return true;
+
+ switch (MCELF::GetBinding(D)) {
+ default:
+ llvm_unreachable("Unknown binding");
+ case ELF::STB_LOCAL:
+ return false;
+ case ELF::STB_GLOBAL:
+ return false;
+ case ELF::STB_WEAK:
+ case ELF::STB_GNU_UNIQUE:
+ return true;
+ }
}
void ELFObjectWriter::RecordRelocation(MCAssembler &Asm,
SectionIndexMap[&Section] = Index++;
}
+ std::vector<const MCSectionELF *> RelSections;
+
for (MCAssembler::iterator it = Asm.begin(),
ie = Asm.end(); it != ie; ++it) {
const MCSectionData &SD = *it;
if (MCSectionData *RelSD = createRelocationSection(Asm, SD)) {
const MCSectionELF *RelSection =
static_cast<const MCSectionELF *>(&RelSD->getSection());
- SectionIndexMap[RelSection] = Index++;
+ RelSections.push_back(RelSection);
}
}
+
+ // Put relocation sections close together. The linker reads them
+ // first, so this improves cache locality.
+ for (const MCSectionELF * Sec: RelSections)
+ SectionIndexMap[Sec] = Index++;
}
void ELFObjectWriter::computeSymbolTable(
return Ret;
}
-uint64_t ELFObjectWriter::GetSectionFileSize(const MCAsmLayout &Layout,
- const MCSectionData &SD) {
- if (IsELFMetaDataSection(SD))
- return DataSectionSize(SD);
- return Layout.getSectionFileSize(&SD);
-}
-
uint64_t ELFObjectWriter::GetSectionAddressSize(const MCAsmLayout &Layout,
const MCSectionData &SD) {
if (IsELFMetaDataSection(SD))
return Layout.getSectionAddressSize(&SD);
}
-void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm,
+void ELFObjectWriter::writeDataSectionData(MCAssembler &Asm,
const MCAsmLayout &Layout,
- const MCSectionELF &Section) {
- const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
-
- uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment());
- WriteZeros(Padding);
-
+ const MCSectionData &SD) {
if (IsELFMetaDataSection(SD)) {
for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e;
++i) {
}
void ELFObjectWriter::writeSectionHeader(
- MCAssembler &Asm, const GroupMapTy &GroupMap, const MCAsmLayout &Layout,
+ ArrayRef<const MCSectionELF *> Sections, MCAssembler &Asm,
+ const GroupMapTy &GroupMap, const MCAsmLayout &Layout,
const SectionIndexMapTy &SectionIndexMap,
const SectionOffsetMapTy &SectionOffsetMap) {
- const unsigned NumSections = Asm.size() + 1;
-
- std::vector<const MCSectionELF*> Sections;
- Sections.resize(NumSections - 1);
-
- for (SectionIndexMapTy::const_iterator i=
- SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) {
- const std::pair<const MCSectionELF*, uint32_t> &p = *i;
- Sections[p.second - 1] = p.first;
- }
+ const unsigned NumSections = Asm.size();
// Null section first.
uint64_t FirstSectionSize =
- NumSections >= ELF::SHN_LORESERVE ? NumSections : 0;
+ (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0;
uint32_t FirstSectionLink =
ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0;
WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0);
- for (unsigned i = 0; i < NumSections - 1; ++i) {
+ for (unsigned i = 0; i < NumSections; ++i) {
const MCSectionELF &Section = *Sections[i];
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
uint32_t GroupSymbolIndex;
}
}
-void ELFObjectWriter::ComputeSectionOrder(MCAssembler &Asm,
- std::vector<const MCSectionELF*> &Sections) {
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it) {
- const MCSectionELF &Section =
- static_cast<const MCSectionELF &>(it->getSection());
- if (Section.getType() == ELF::SHT_GROUP)
- Sections.push_back(&Section);
- }
-
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it) {
- const MCSectionELF &Section =
- static_cast<const MCSectionELF &>(it->getSection());
- if (Section.getType() != ELF::SHT_GROUP &&
- Section.getType() != ELF::SHT_REL &&
- Section.getType() != ELF::SHT_RELA)
- Sections.push_back(&Section);
- }
-
- for (MCAssembler::iterator it = Asm.begin(),
- ie = Asm.end(); it != ie; ++it) {
- const MCSectionELF &Section =
- static_cast<const MCSectionELF &>(it->getSection());
- if (Section.getType() == ELF::SHT_REL ||
- Section.getType() == ELF::SHT_RELA)
- Sections.push_back(&Section);
- }
-}
-
void ELFObjectWriter::WriteObject(MCAssembler &Asm,
const MCAsmLayout &Layout) {
GroupMapTy GroupMap;
const_cast<MCAsmLayout&>(Layout),
SectionIndexMap);
- uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
- uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) :
- sizeof(ELF::Elf32_Ehdr);
- uint64_t FileOff = HeaderSize;
-
+ unsigned NumSections = Asm.size();
std::vector<const MCSectionELF*> Sections;
- ComputeSectionOrder(Asm, Sections);
- unsigned NumSections = Sections.size();
+ Sections.resize(NumSections);
+
+ for (auto &Pair : SectionIndexMap)
+ Sections[Pair.second - 1] = Pair.first;
+
SectionOffsetMapTy SectionOffsetMap;
- for (unsigned i = 0; i < NumSections; ++i) {
+ // Write out the ELF header ...
+ WriteHeader(Asm, NumSections + 1);
+
+ // ... then the sections ...
+ for (unsigned i = 0; i < NumSections; ++i) {
const MCSectionELF &Section = *Sections[i];
const MCSectionData &SD = Asm.getOrCreateSectionData(Section);
-
- FileOff = RoundUpToAlignment(FileOff, SD.getAlignment());
+ uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment());
+ WriteZeros(Padding);
// Remember the offset into the file for this section.
- SectionOffsetMap[&Section] = FileOff;
+ SectionOffsetMap[&Section] = OS.tell();
- // Get the size of the section in the output file (including padding).
- FileOff += GetSectionFileSize(Layout, SD);
+ writeDataSectionData(Asm, Layout, SD);
}
- FileOff = RoundUpToAlignment(FileOff, NaturalAlignment);
-
- const unsigned SectionHeaderOffset = FileOff;
-
- // Write out the ELF header ...
- WriteHeader(Asm, SectionHeaderOffset, NumSections + 1);
-
- // ... then the sections ...
- for (unsigned i = 0; i < NumSections; ++i)
- WriteDataSectionData(Asm, Layout, *Sections[i]);
-
+ uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
uint64_t Padding = OffsetToAlignment(OS.tell(), NaturalAlignment);
WriteZeros(Padding);
+ const unsigned SectionHeaderOffset = OS.tell();
+
// ... then the section header table ...
- writeSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, SectionOffsetMap);
+ writeSectionHeader(Sections, Asm, GroupMap, Layout, SectionIndexMap,
+ SectionOffsetMap);
+
+ if (is64Bit()) {
+ uint64_t Val = SectionHeaderOffset;
+ if (sys::IsLittleEndianHost != IsLittleEndian)
+ sys::swapByteOrder(Val);
+ OS.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+ offsetof(ELF::Elf64_Ehdr, e_shoff));
+ } else {
+ uint32_t Val = SectionHeaderOffset;
+ if (sys::IsLittleEndianHost != IsLittleEndian)
+ sys::swapByteOrder(Val);
+ OS.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+ offsetof(ELF::Elf32_Ehdr, e_shoff));
+ }
}
bool ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(
- const MCAssembler &Asm, const MCSymbolData &DataA,
- const MCSymbolData *DataB, const MCFragment &FB, bool InSet,
- bool IsPCRel) const {
- if (!InSet && (::isWeak(DataA) || (DataB && ::isWeak(*DataB))))
- return false;
- return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(
- Asm, DataA, DataB, FB, InSet, IsPCRel);
+ const MCAssembler &Asm, const MCSymbolData &DataA, const MCFragment &FB,
+ bool InSet, bool IsPCRel) const {
+ if (IsPCRel) {
+ assert(!InSet);
+ if (::isWeak(DataA))
+ return false;
+ }
+ return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, FB,
+ InSet, IsPCRel);
}
bool ELFObjectWriter::isWeak(const MCSymbolData &SD) const {
- return ::isWeak(SD);
+ if (::isWeak(SD))
+ return true;
+
+ // It is invalid to replace a reference to a global in a comdat
+ // with a reference to a local since out of comdat references
+ // to a local are forbidden.
+ // We could try to return false for more cases, like the reference
+ // being in the same comdat or Sym being an alias to another global,
+ // but it is not clear if it is worth the effort.
+ if (MCELF::GetBinding(SD) != ELF::STB_GLOBAL)
+ return false;
+
+ const MCSymbol &Sym = SD.getSymbol();
+ if (!Sym.isInSection())
+ return false;
+
+ const auto &Sec = cast<MCSectionELF>(Sym.getSection());
+ return Sec.getGroup();
}
MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW,