void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { // Section symbols are used as definitions for undefined symbols with matching // names. If there are multiple sections with the same name, the first one is // used. for (const MCSection &Sec : Asm) { const MCSymbol *Begin = Sec.getBeginSymbol(); if (!Begin) continue; const MCSymbol *Alias = Asm.getContext().lookupSymbol(Begin->getName()); if (!Alias || !Alias->isUndefined()) continue; Renames.insert( std::make_pair(cast<MCSymbolELF>(Alias), cast<MCSymbolELF>(Begin))); } // The presence of symbol versions causes undefined symbols and // versions declared with @@@ to be renamed. for (const MCSymbol &A : Asm.symbols()) { const auto &Alias = cast<MCSymbolELF>(A); // Not an alias. if (!Alias.isVariable()) continue; auto *Ref = dyn_cast<MCSymbolRefExpr>(Alias.getVariableValue()); if (!Ref) continue; const auto &Symbol = cast<MCSymbolELF>(Ref->getSymbol()); StringRef AliasName = Alias.getName(); size_t Pos = AliasName.find('@'); if (Pos == StringRef::npos) continue; // Aliases defined with .symvar copy the binding from the symbol they alias. // This is the first place we are able to copy this information. Alias.setExternal(Symbol.isExternal()); Alias.setBinding(Symbol.getBinding()); StringRef Rest = AliasName.substr(Pos); if (!Symbol.isUndefined() && !Rest.startswith("@@@")) continue; // FIXME: produce a better error message. if (Symbol.isUndefined() && Rest.startswith("@@") && !Rest.startswith("@@@")) report_fatal_error("A @@ version cannot be undefined"); Renames.insert(std::make_pair(&Symbol, &Alias)); } }
void MachObjectWriter::markAbsoluteVariableSymbols(MCAssembler &Asm, const MCAsmLayout &Layout) { for (MCSymbolData &SD : Asm.symbols()) { if (!SD.getSymbol().isVariable()) continue; // Is the variable is a symbol difference (SA - SB + C) expression, // and neither symbol is external, mark the variable as absolute. const MCExpr *Expr = SD.getSymbol().getVariableValue(); MCValue Value; if (Expr->EvaluateAsRelocatable(Value, &Layout, nullptr)) { if (Value.getSymA() && Value.getSymB()) const_cast<MCSymbol*>(&SD.getSymbol())->setAbsolute(); } } }
void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { // "Define" each section & symbol. This creates section & symbol // entries in the staging area. static_assert(sizeof(((COFF::AuxiliaryFile *)nullptr)->FileName) == COFF::SymbolSize, "size mismatch for COFF::AuxiliaryFile::FileName"); for (auto FI = Asm.file_names_begin(), FE = Asm.file_names_end(); FI != FE; ++FI) { // round up to calculate the number of auxiliary symbols required unsigned Count = (FI->size() + COFF::SymbolSize - 1) / COFF::SymbolSize; COFFSymbol *file = createSymbol(".file"); file->Data.SectionNumber = COFF::IMAGE_SYM_DEBUG; file->Data.StorageClass = COFF::IMAGE_SYM_CLASS_FILE; file->Aux.resize(Count); unsigned Offset = 0; unsigned Length = FI->size(); for (auto & Aux : file->Aux) { Aux.AuxType = ATFile; if (Length > COFF::SymbolSize) { memcpy(Aux.Aux.File.FileName, FI->c_str() + Offset, COFF::SymbolSize); Length = Length - COFF::SymbolSize; } else { memcpy(Aux.Aux.File.FileName, FI->c_str() + Offset, Length); memset(&Aux.Aux.File.FileName[Length], 0, COFF::SymbolSize - Length); Length = 0; } Offset = Offset + COFF::SymbolSize; } } for (const auto & Section : Asm) DefineSection(Section); for (MCSymbolData &SD : Asm.symbols()) if (ExportSymbol(SD, Asm)) DefineSymbol(SD, Asm, Layout); }
/// computeSymbolTable - Compute the symbol table data void MachObjectWriter::computeSymbolTable( MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData, std::vector<MachSymbolData> &ExternalSymbolData, std::vector<MachSymbolData> &UndefinedSymbolData) { // Build section lookup table. DenseMap<const MCSection*, uint8_t> SectionIndexMap; unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it, ++Index) SectionIndexMap[&*it] = Index; assert(Index <= 256 && "Too many sections!"); // Build the string table. for (const MCSymbol &Symbol : Asm.symbols()) { if (!Asm.isSymbolLinkerVisible(Symbol)) continue; StringTable.add(Symbol.getName()); } StringTable.finalize(); // Build the symbol arrays but only for non-local symbols. // // The particular order that we collect and then sort the symbols is chosen to // match 'as'. Even though it doesn't matter for correctness, this is // important for letting us diff .o files. for (const MCSymbol &Symbol : Asm.symbols()) { // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (!Symbol.isExternal() && !Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.Symbol = &Symbol; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isUndefined()) { MSD.SectionIndex = 0; UndefinedSymbolData.push_back(MSD); } else if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; ExternalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); ExternalSymbolData.push_back(MSD); } } // Now add the data for local symbols. for (const MCSymbol &Symbol : Asm.symbols()) { // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (Symbol.isExternal() || Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.Symbol = &Symbol; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; LocalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); LocalSymbolData.push_back(MSD); } } // External and undefined symbols are required to be in lexicographic order. std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; for (auto *SymbolData : {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData}) for (MachSymbolData &Entry : *SymbolData) Entry.Symbol->setIndex(Index++); for (const MCSection &Section : Asm) { for (RelAndSymbol &Rel : Relocations[&Section]) { if (!Rel.Sym) continue; // Set the Index and the IsExtern bit. unsigned Index = Rel.Sym->getIndex(); assert(isInt<24>(Index)); if (IsLittleEndian) Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (~0U << 24)) | Index | (1 << 27); else Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4); } } }
/// ComputeSymbolTable - Compute the symbol table data void MachObjectWriter::ComputeSymbolTable( MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData, std::vector<MachSymbolData> &ExternalSymbolData, std::vector<MachSymbolData> &UndefinedSymbolData) { // Build section lookup table. DenseMap<const MCSection*, uint8_t> SectionIndexMap; unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it, ++Index) SectionIndexMap[&it->getSection()] = Index; assert(Index <= 256 && "Too many sections!"); // Build the string table. for (MCSymbolData &SD : Asm.symbols()) { const MCSymbol &Symbol = SD.getSymbol(); if (!Asm.isSymbolLinkerVisible(Symbol)) continue; StringTable.add(Symbol.getName()); } StringTable.finalize(StringTableBuilder::MachO); // Build the symbol arrays but only for non-local symbols. // // The particular order that we collect and then sort the symbols is chosen to // match 'as'. Even though it doesn't matter for correctness, this is // important for letting us diff .o files. for (MCSymbolData &SD : Asm.symbols()) { const MCSymbol &Symbol = SD.getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (!SD.isExternal() && !Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.SymbolData = &SD; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isUndefined()) { MSD.SectionIndex = 0; UndefinedSymbolData.push_back(MSD); } else if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; ExternalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); ExternalSymbolData.push_back(MSD); } } // Now add the data for local symbols. for (MCSymbolData &SD : Asm.symbols()) { const MCSymbol &Symbol = SD.getSymbol(); // Ignore non-linker visible symbols. if (!Asm.isSymbolLinkerVisible(Symbol)) continue; if (SD.isExternal() || Symbol.isUndefined()) continue; MachSymbolData MSD; MSD.SymbolData = &SD; MSD.StringIndex = StringTable.getOffset(Symbol.getName()); if (Symbol.isAbsolute()) { MSD.SectionIndex = 0; LocalSymbolData.push_back(MSD); } else { MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); assert(MSD.SectionIndex && "Invalid section index!"); LocalSymbolData.push_back(MSD); } } // External and undefined symbols are required to be in lexicographic order. std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); // Set the symbol indices. Index = 0; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); }
void ELFObjectWriter::computeSymbolTable( MCAssembler &Asm, const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap, SectionOffsetsTy &SectionOffsets) { MCContext &Ctx = Asm.getContext(); SymbolTableWriter Writer(*this, is64Bit()); // Symbol table unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; MCSectionELF *SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, ""); SymtabSection->setAlignment(is64Bit() ? 8 : 4); SymbolTableIndex = addToSectionTable(SymtabSection); align(SymtabSection->getAlignment()); uint64_t SecStart = getStream().tell(); // The first entry is the undefined symbol entry. Writer.writeSymbol(0, 0, 0, 0, 0, 0, false); std::vector<ELFSymbolData> LocalSymbolData; std::vector<ELFSymbolData> ExternalSymbolData; // Add the data for the symbols. bool HasLargeSectionIndex = false; for (const MCSymbol &S : Asm.symbols()) { const auto &Symbol = cast<MCSymbolELF>(S); bool Used = Symbol.isUsedInReloc(); bool WeakrefUsed = Symbol.isWeakrefUsedInReloc(); bool isSignature = Symbol.isSignature(); if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature, Renames.count(&Symbol))) continue; if (Symbol.isTemporary() && Symbol.isUndefined()) { Ctx.reportError(SMLoc(), "Undefined temporary symbol"); continue; } ELFSymbolData MSD; MSD.Symbol = cast<MCSymbolELF>(&Symbol); bool Local = Symbol.getBinding() == ELF::STB_LOCAL; assert(Local || !Symbol.isTemporary()); if (Symbol.isAbsolute()) { MSD.SectionIndex = ELF::SHN_ABS; } else if (Symbol.isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; } else if (Symbol.isUndefined()) { if (isSignature && !Used) { MSD.SectionIndex = RevGroupMap.lookup(&Symbol); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } else { MSD.SectionIndex = ELF::SHN_UNDEF; } } else { const MCSectionELF &Section = static_cast<const MCSectionELF &>(Symbol.getSection()); MSD.SectionIndex = SectionIndexMap.lookup(&Section); assert(MSD.SectionIndex && "Invalid section index!"); if (MSD.SectionIndex >= ELF::SHN_LORESERVE) HasLargeSectionIndex = true; } // The @@@ in symbol version is replaced with @ in undefined symbols and @@ // in defined ones. // // FIXME: All name handling should be done before we get to the writer, // including dealing with GNU-style version suffixes. Fixing this isn't // trivial. // // We thus have to be careful to not perform the symbol version replacement // blindly: // // The ELF format is used on Windows by the MCJIT engine. Thus, on // Windows, the ELFObjectWriter can encounter symbols mangled using the MS // Visual Studio C++ name mangling scheme. Symbols mangled using the MSVC // C++ name mangling can legally have "@@@" as a sub-string. In that case, // the EFLObjectWriter should not interpret the "@@@" sub-string as // specifying GNU-style symbol versioning. The ELFObjectWriter therefore // checks for the MSVC C++ name mangling prefix which is either "?", "@?", // "__imp_?" or "__imp_@?". // // It would have been interesting to perform the MS mangling prefix check // only when the target triple is of the form *-pc-windows-elf. But, it // seems that this information is not easily accessible from the // ELFObjectWriter. StringRef Name = Symbol.getName(); SmallString<32> Buf; if (!Name.startswith("?") && !Name.startswith("@?") && !Name.startswith("__imp_?") && !Name.startswith("__imp_@?")) { // This symbol isn't following the MSVC C++ name mangling convention. We // can thus safely interpret the @@@ in symbol names as specifying symbol // versioning. size_t Pos = Name.find("@@@"); if (Pos != StringRef::npos) { Buf += Name.substr(0, Pos); unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; Buf += Name.substr(Pos + Skip); Name = VersionSymSaver.save(Buf.c_str()); } } // Sections have their own string table if (Symbol.getType() != ELF::STT_SECTION) { MSD.Name = Name; StrTabBuilder.add(Name); } if (Local) LocalSymbolData.push_back(MSD); else ExternalSymbolData.push_back(MSD); } // This holds the .symtab_shndx section index. unsigned SymtabShndxSectionIndex = 0; if (HasLargeSectionIndex) { MCSectionELF *SymtabShndxSection = Ctx.getELFSection(".symtab_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection); SymtabShndxSection->setAlignment(4); } ArrayRef<std::string> FileNames = Asm.getFileNames(); for (const std::string &Name : FileNames) StrTabBuilder.add(Name); StrTabBuilder.finalize(); // File symbols are emitted first and handled separately from normal symbols, // i.e. a non-STT_FILE symbol with the same name may appear. for (const std::string &Name : FileNames) Writer.writeSymbol(StrTabBuilder.getOffset(Name), ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT, ELF::SHN_ABS, true); // Symbols are required to be in lexicographic order. array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); // Set the symbol indices. Local symbols must come before all other // symbols with non-local bindings. unsigned Index = FileNames.size() + 1; for (ELFSymbolData &MSD : LocalSymbolData) { unsigned StringIndex = MSD.Symbol->getType() == ELF::STT_SECTION ? 0 : StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); } // Write the symbol table entries. LastLocalSymbolIndex = Index; for (ELFSymbolData &MSD : ExternalSymbolData) { unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name); MSD.Symbol->setIndex(Index++); writeSymbol(Writer, StringIndex, MSD, Layout); assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL); } uint64_t SecEnd = getStream().tell(); SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd); ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes(); if (ShndxIndexes.empty()) { assert(SymtabShndxSectionIndex == 0); return; } assert(SymtabShndxSectionIndex != 0); SecStart = getStream().tell(); const MCSectionELF *SymtabShndxSection = SectionTable[SymtabShndxSectionIndex - 1]; for (uint32_t Index : ShndxIndexes) write(Index); SecEnd = getStream().tell(); SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd); }