diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-09-27 08:58:26 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-09-27 08:58:26 +0000 |
commit | a72d87899bc1bfdb17744aae2545a21b3630d3c1 (patch) | |
tree | 548fc9c941102b26c7cc744a869bb427d480b02e /lib/MC | |
parent | 295646274276c6814d970bed86d3b4ff76ba3ee3 (diff) | |
download | external_llvm-a72d87899bc1bfdb17744aae2545a21b3630d3c1.zip external_llvm-a72d87899bc1bfdb17744aae2545a21b3630d3c1.tar.gz external_llvm-a72d87899bc1bfdb17744aae2545a21b3630d3c1.tar.bz2 |
MC-COFF: Drop empty sections, and label symbols. Convert relocations
targeted at symbols into relocations relative to the containing section.
Patch by Nathan Jeffords!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@114823 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/MC')
-rw-r--r-- | lib/MC/WinCOFFObjectWriter.cpp | 245 |
1 files changed, 163 insertions, 82 deletions
diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index eeb2b96..d686098 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -55,6 +55,9 @@ struct AuxSymbol { COFF::Auxiliary Aux; }; +class COFFSymbol; +class COFFSection; + class COFFSymbol { public: COFF::symbol Data; @@ -65,12 +68,16 @@ public: size_t Index; AuxiliarySymbols Aux; COFFSymbol *Other; + COFFSection *Section; + int Relocations; MCSymbolData const *MCData; - COFFSymbol(llvm::StringRef name, size_t index); + COFFSymbol(llvm::StringRef name); size_t size() const; void set_name_offset(uint32_t Offset); + + bool should_keep() const; }; // This class contains staging data for a COFF relocation entry. @@ -91,10 +98,10 @@ public: std::string Name; size_t Number; MCSectionData const *MCData; - COFFSymbol *Symb; + COFFSymbol *Symbol; relocations Relocations; - COFFSection(llvm::StringRef name, size_t Index); + COFFSection(llvm::StringRef name); static size_t size(); }; @@ -141,18 +148,20 @@ public: COFFSymbol *createSymbol(llvm::StringRef Name); COFFSection *createSection(llvm::StringRef Name); - void InitCOFFEntity(COFFSymbol &Symbol); - void InitCOFFEntity(COFFSection &Section); - template <typename object_t, typename list_t> object_t *createCOFFEntity(llvm::StringRef Name, list_t &List); void DefineSection(MCSectionData const &SectionData); void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler); - bool ExportSection(COFFSection *S); + void MakeSymbolReal(COFFSymbol &S, size_t Index); + void MakeSectionReal(COFFSection &S, size_t Number); + + bool ExportSection(COFFSection const *S); bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + bool IsPhysicalSection(COFFSection *S); + // Entity writing methods. void WriteFileHeader(const COFF::header &Header); @@ -198,9 +207,12 @@ static inline void write_uint8_le(void *Data, uint8_t const &Value) { //------------------------------------------------------------------------------ // Symbol class implementation -COFFSymbol::COFFSymbol(llvm::StringRef name, size_t index) - : Name(name.begin(), name.end()), Index(-1) - , Other(NULL), MCData(NULL) { +COFFSymbol::COFFSymbol(llvm::StringRef name) + : Name(name.begin(), name.end()) + , Other(NULL) + , Section(NULL) + , Relocations(0) + , MCData(NULL) { memset(&Data, 0, sizeof(Data)); } @@ -216,12 +228,41 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { write_uint32_le(Data.Name + 4, Offset); } +/// logic to decide if the symbol should be reported in the symbol table +bool COFFSymbol::should_keep() const { + // no section means its external, keep it + if (Section == NULL) + return true; + + // if it has relocations pointing at it, keep it + if (Relocations > 0) { + assert(Section->Number != -1 && "Sections with relocations must be real!"); + return true; + } + + // if the section its in is being droped, drop it + if (Section->Number == -1) + return false; + + // if it is the section symbol, keep it + if (Section->Symbol == this) + return true; + + // if its temporary, drop it + if (MCData && MCData->getSymbol().isTemporary()) + return false; + + // otherwise, keep it + return true; +} + //------------------------------------------------------------------------------ // Section class implementation -COFFSection::COFFSection(llvm::StringRef name, size_t Index) - : Name(name), Number(Index + 1) - , MCData(NULL), Symb(NULL) { +COFFSection::COFFSection(llvm::StringRef name) + : Name(name) + , MCData(NULL) + , Symbol(NULL) { memset(&Header, 0, sizeof(Header)); } @@ -298,45 +339,12 @@ COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { return createCOFFEntity<COFFSection>(Name, Sections); } -/// This function initializes a symbol by entering its name into the string -/// table if it is too long to fit in the symbol table header. -void WinCOFFObjectWriter::InitCOFFEntity(COFFSymbol &S) { - if (S.Name.size() > COFF::NameSize) { - size_t StringTableEntry = Strings.insert(S.Name.c_str()); - - S.set_name_offset(StringTableEntry); - } else - memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); -} - -/// This function initializes a section by entering its name into the string -/// table if it is too long to fit in the section table header. -void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { - if (S.Name.size() > COFF::NameSize) { - size_t StringTableEntry = Strings.insert(S.Name.c_str()); - - // FIXME: Why is this number 999999? This number is never mentioned in the - // spec. I'm assuming this is due to the printed value needing to fit into - // the S.Header.Name field. In which case why not 9999999 (7 9's instead of - // 6)? The spec does not state if this entry should be null terminated in - // this case, and thus this seems to be the best way to do it. I think I - // just solved my own FIXME... - if (StringTableEntry > 999999) - report_fatal_error("COFF string table is greater than 999999 bytes."); - - sprintf(S.Header.Name, "/%d", (unsigned)StringTableEntry); - } else - memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); -} - /// A template used to lookup or create a symbol/section, and initialize it if /// needed. template <typename object_t, typename list_t> object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name, list_t &List) { - object_t *Object = new object_t(Name, List.size()); - - InitCOFFEntity(*Object); + object_t *Object = new object_t(Name); List.push_back(Object); @@ -353,15 +361,14 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { COFFSection *coff_section = createSection(Sec.getSectionName()); COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName()); - coff_section->Symb = coff_symbol; + coff_section->Symbol = coff_symbol; + coff_symbol->Section = coff_section; coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - coff_symbol->Data.SectionNumber = coff_section->Number; // In this case the auxiliary symbol is a Section Definition. coff_symbol->Aux.resize(1); memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); coff_symbol->Aux[0].AuxType = ATSectionDefinition; - coff_symbol->Aux[0].Aux.SectionDefinition.Number = coff_section->Number; coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection(); coff_section->Header.Characteristics = Sec.getCharacteristics(); @@ -394,7 +401,9 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { /// This function takes a section data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, - MCAssembler &Assembler) { + MCAssembler &Assembler) { + assert(!SymbolData.getSymbol().isVariable() + && "Cannot define a symbol that is a variable!"); COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName()); coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0; @@ -405,7 +414,7 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, bool external = SymbolData.isExternal() || (SymbolData.Fragment == NULL); coff_symbol->Data.StorageClass = - external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; + external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_LABEL; } if (SymbolData.getFlags() & COFF::SF_WeakReference) { @@ -438,14 +447,50 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; } + if (SymbolData.Fragment != NULL) + coff_symbol->Section = SectionMap[SymbolData.Fragment->getParent()]; + // Bind internal COFF symbol to MC symbol. coff_symbol->MCData = &SymbolData; SymbolMap[&SymbolData] = coff_symbol; } -bool WinCOFFObjectWriter::ExportSection(COFFSection *S) { - return (S->Header.Characteristics - & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; +/// making a section real involves assigned it a number and putting +/// name into the string table if needed +void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + // FIXME: Why is this number 999999? This number is never mentioned in the + // spec. I'm assuming this is due to the printed value needing to fit into + // the S.Header.Name field. In which case why not 9999999 (7 9's instead of + // 6)? The spec does not state if this entry should be null terminated in + // this case, and thus this seems to be the best way to do it. I think I + // just solved my own FIXME... + if (StringTableEntry > 999999) + report_fatal_error("COFF string table is greater than 999999 bytes."); + + std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry)); + } else + std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); + + S.Number = Number; + S.Symbol->Data.SectionNumber = S.Number; + S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number; +} + +void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + S.set_name_offset(StringTableEntry); + } else + std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); + S.Index = Index; +} + +bool WinCOFFObjectWriter::ExportSection(COFFSection const *S) { + return !S->MCData->getFragmentList().empty(); } bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, @@ -455,8 +500,14 @@ bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, // return Asm.isSymbolLinkerVisible (&SymbolData); - // For now, all symbols are exported, the linker will sort it out for us. - return true; + // For now, all non-variable symbols are exported, + // the linker will sort the rest out for us. + return !SymbolData.getSymbol().isVariable(); +} + +bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) { + return (S->Header.Characteristics + & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; } //------------------------------------------------------------------------------ @@ -548,7 +599,7 @@ void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { // "Define" each section & symbol. This creates section & symbol - // entries in the staging area and gives them their final indexes. + // entries in the staging area. for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) DefineSection(*i); @@ -600,7 +651,15 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); - Reloc.Symb = coff_symbol; + + // turn relocations for temporary symbols into section relocations + if (coff_symbol->MCData->getSymbol().isTemporary()) { + Reloc.Symb = coff_symbol->Section->Symbol; + FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment); + } else + Reloc.Symb = coff_symbol; + + ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); @@ -634,6 +693,16 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { // Assign symbol and section indexes and offsets. + Header.NumberOfSections = 0; + + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if (Layout.getSectionSize((*i)->MCData) > 0) { + MakeSectionReal(**i, ++Header.NumberOfSections); + } else { + (*i)->Number = -1; + } + } Header.NumberOfSymbols = 0; @@ -641,32 +710,35 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, COFFSymbol *coff_symbol = *i; MCSymbolData const *SymbolData = coff_symbol->MCData; - coff_symbol->Index = Header.NumberOfSymbols++; - // Update section number & offset for symbols that have them. if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { - COFFSection *coff_section = SectionMap[SymbolData->Fragment->getParent()]; + assert(coff_symbol->Section != NULL); - coff_symbol->Data.SectionNumber = coff_section->Number; + coff_symbol->Data.SectionNumber = coff_symbol->Section->Number; coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + SymbolData->Offset; } - // Update auxiliary symbol info. - coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); - Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + if (coff_symbol->should_keep()) { + MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } else + coff_symbol->Index = -1; } // Fixup weak external references. for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { - COFFSymbol *symb = *i; - - if (symb->Other != NULL) { - assert(symb->Aux.size() == 1 && + COFFSymbol *coff_symbol = *i; + if (coff_symbol->Other != NULL) { + assert(coff_symbol->Index != -1); + assert(coff_symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!"); - assert(symb->Aux[0].AuxType == ATWeakExternal && + assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && "Symbol's aux symbol must be a Weak External!"); - symb->Aux[0].Aux.WeakExternal.TagIndex = symb->Other->Index; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; } } @@ -675,18 +747,19 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, unsigned offset = 0; offset += COFF::HeaderSize; - offset += COFF::SectionSize * Asm.size(); - - Header.NumberOfSections = Sections.size(); + offset += COFF::SectionSize * Header.NumberOfSections; for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) { COFFSection *Sec = SectionMap[i]; + if (Sec->Number == -1) + continue; + Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i); - if (ExportSection(Sec)) { + if (IsPhysicalSection(Sec)) { Sec->Header.PointerToRawData = offset; offset += Sec->Header.SizeOfRawData; @@ -700,13 +773,15 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, for (relocations::iterator cr = Sec->Relocations.begin(), er = Sec->Relocations.end(); - cr != er; cr++) { + cr != er; ++cr) { + assert((*cr).Symb->Index != -1); (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; } } - assert(Sec->Symb->Aux.size() == 1 && "Section's symbol must have one aux!"); - AuxSymbol &Aux = Sec->Symb->Aux[0]; + assert(Sec->Symbol->Aux.size() == 1 + && "Section's symbol must have one aux!"); + AuxSymbol &Aux = Sec->Symbol->Aux[0]; assert(Aux.AuxType == ATSectionDefinition && "Section's symbol's aux symbol must be a Section Definition!"); Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; @@ -728,11 +803,16 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, MCAssembler::const_iterator j, je; for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) - WriteSectionHeader((*i)->Header); + if ((*i)->Number != -1) + WriteSectionHeader((*i)->Header); for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(), je = Asm.end(); - (i != ie) && (j != je); i++, j++) { + (i != ie) && (j != je); ++i, ++j) { + + if ((*i)->Number == -1) + continue; + if ((*i)->Header.PointerToRawData != 0) { assert(OS.tell() == (*i)->Header.PointerToRawData && "Section::PointerToRawData is insane!"); @@ -759,7 +839,8 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, "Header::PointerToSymbolTable is insane!"); for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) - WriteSymbol(*i); + if ((*i)->Index != -1) + WriteSymbol(*i); OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } |