Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 1 | //===- subzero/src/IceELFObjectWriter.cpp - ELF object file writer --------===// |
| 2 | // |
| 3 | // The Subzero Code Generator |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 11 | /// \brief Defines the writer for ELF relocatable object files. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 12 | /// |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 13 | //===----------------------------------------------------------------------===// |
| 14 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 15 | #include "IceELFObjectWriter.h" |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 16 | |
John Porto | aff4ccf | 2015-06-10 16:35:06 -0700 | [diff] [blame] | 17 | #include "IceAssembler.h" |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 18 | #include "IceDefs.h" |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 19 | #include "IceELFSection.h" |
| 20 | #include "IceELFStreamer.h" |
| 21 | #include "IceGlobalContext.h" |
| 22 | #include "IceGlobalInits.h" |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 23 | #include "IceInst.h" |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 24 | #include "IceOperand.h" |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 25 | |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 26 | #include "llvm/Support/ELF.h" |
| 27 | #include "llvm/Support/MathExtras.h" |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 28 | |
| 29 | namespace Ice { |
| 30 | |
| 31 | namespace { |
| 32 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 33 | constexpr struct { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 34 | bool IsELF64; |
| 35 | uint16_t ELFMachine; |
| 36 | uint32_t ELFFlags; |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 37 | } ELFTargetInfo[TargetArch_NUM] = { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 38 | #define X(tag, str, is_elf64, e_machine, e_flags) \ |
Antonio Maiorano | debdfa2 | 2020-11-10 16:28:34 -0500 | [diff] [blame] | 39 | {is_elf64, e_machine, e_flags}, |
Jim Stichnoth | d9dc82e | 2015-03-03 17:06:33 -0800 | [diff] [blame] | 40 | TARGETARCH_TABLE |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 41 | #undef X |
| 42 | }; |
| 43 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 44 | bool isELF64(const ClFlags &Flags) { |
| 45 | const TargetArch Arch = Flags.getTargetArch(); |
| 46 | if (Arch >= TargetArch_NUM) { |
| 47 | llvm_unreachable("Invalid target arch for isELF64"); |
| 48 | return false; |
| 49 | } |
| 50 | |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 51 | return ELFTargetInfo[Arch].IsELF64; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | uint16_t getELFMachine(TargetArch Arch) { |
| 55 | if (Arch < TargetArch_NUM) |
| 56 | return ELFTargetInfo[Arch].ELFMachine; |
| 57 | llvm_unreachable("Invalid target arch for getELFMachine"); |
| 58 | return EM_NONE; |
| 59 | } |
| 60 | |
| 61 | uint32_t getELFFlags(TargetArch Arch) { |
| 62 | if (Arch < TargetArch_NUM) |
| 63 | return ELFTargetInfo[Arch].ELFFlags; |
| 64 | llvm_unreachable("Invalid target arch for getELFFlags"); |
| 65 | return 0; |
| 66 | } |
| 67 | |
| 68 | } // end of anonymous namespace |
| 69 | |
| 70 | ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out) |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 71 | : Ctx(Ctx), Str(Out), ELF64(isELF64(getFlags())) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 72 | // Create the special bookkeeping sections now. |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 73 | constexpr char NullSectionName[] = ""; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 74 | NullSection = new (Ctx.allocate<ELFSection>()) |
| 75 | ELFSection(NullSectionName, SHT_NULL, 0, 0, 0); |
| 76 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 77 | constexpr char ShStrTabName[] = ".shstrtab"; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 78 | ShStrTab = new (Ctx.allocate<ELFStringTableSection>()) |
| 79 | ELFStringTableSection(ShStrTabName, SHT_STRTAB, 0, 1, 0); |
| 80 | ShStrTab->add(ShStrTabName); |
| 81 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 82 | constexpr char SymTabName[] = ".symtab"; |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 83 | const Elf64_Xword SymTabAlign = ELF64 ? 8 : 4; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 84 | const Elf64_Xword SymTabEntSize = |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 85 | ELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 86 | static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16, |
| 87 | "Elf_Sym sizes cannot be derived from sizeof"); |
| 88 | SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0, |
| 89 | SymTabAlign, SymTabEntSize); |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 90 | SymTab->createNullSymbol(NullSection, &Ctx); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 91 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 92 | constexpr char StrTabName[] = ".strtab"; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 93 | StrTab = |
| 94 | createSection<ELFStringTableSection>(StrTabName, SHT_STRTAB, 0, 1, 0); |
| 95 | } |
| 96 | |
| 97 | template <typename T> |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 98 | T *ELFObjectWriter::createSection(const std::string &Name, Elf64_Word ShType, |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 99 | Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
| 100 | Elf64_Xword ShEntsize) { |
| 101 | assert(!SectionNumbersAssigned); |
| 102 | T *NewSection = |
| 103 | new (Ctx.allocate<T>()) T(Name, ShType, ShFlags, ShAddralign, ShEntsize); |
| 104 | ShStrTab->add(Name); |
| 105 | return NewSection; |
| 106 | } |
| 107 | |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 108 | ELFRelocationSection * |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 109 | ELFObjectWriter::createRelocationSection(const ELFSection *RelatedSection) { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 110 | // Choice of RELA vs REL is actually separate from elf64 vs elf32, but in |
| 111 | // practice we've only had .rela for elf64 (x86-64). In the future, the two |
| 112 | // properties may need to be decoupled and the ShEntSize can vary more. |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 113 | const Elf64_Word ShType = ELF64 ? SHT_RELA : SHT_REL; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 114 | const std::string RelPrefix = ELF64 ? ".rela" : ".rel"; |
| 115 | const std::string RelSectionName = RelPrefix + RelatedSection->getName(); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 116 | const Elf64_Xword ShAlign = ELF64 ? 8 : 4; |
| 117 | const Elf64_Xword ShEntSize = ELF64 ? sizeof(Elf64_Rela) : sizeof(Elf32_Rel); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 118 | static_assert(sizeof(Elf64_Rela) == 24 && sizeof(Elf32_Rel) == 8, |
| 119 | "Elf_Rel/Rela sizes cannot be derived from sizeof"); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 120 | constexpr Elf64_Xword ShFlags = 0; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 121 | ELFRelocationSection *RelSection = createSection<ELFRelocationSection>( |
| 122 | RelSectionName, ShType, ShFlags, ShAlign, ShEntSize); |
| 123 | RelSection->setRelatedSection(RelatedSection); |
| 124 | return RelSection; |
| 125 | } |
| 126 | |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 127 | template <typename UserSectionList> |
| 128 | void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, |
| 129 | UserSectionList &UserSections, |
| 130 | RelSectionList &RelSections, |
| 131 | SectionList &AllSections) { |
| 132 | RelSectionList::iterator RelIt = RelSections.begin(); |
| 133 | RelSectionList::iterator RelE = RelSections.end(); |
| 134 | for (ELFSection *UserSection : UserSections) { |
| 135 | UserSection->setNumber(CurSectionNumber++); |
| 136 | UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName())); |
| 137 | AllSections.push_back(UserSection); |
| 138 | if (RelIt != RelE) { |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 139 | ELFRelocationSection *RelSection = *RelIt; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 140 | if (RelSection->getRelatedSection() == UserSection) { |
| 141 | RelSection->setInfoNum(UserSection->getNumber()); |
| 142 | RelSection->setNumber(CurSectionNumber++); |
| 143 | RelSection->setNameStrIndex(ShStrTab->getIndex(RelSection->getName())); |
| 144 | AllSections.push_back(RelSection); |
| 145 | ++RelIt; |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | // Should finish with UserIt at the same time as RelIt. |
| 150 | assert(RelIt == RelE); |
| 151 | return; |
| 152 | } |
| 153 | |
| 154 | void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber, |
| 155 | RelSectionList &RelSections) { |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 156 | for (ELFRelocationSection *S : RelSections) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 157 | S->setLinkNum(SymTabNumber); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 162 | // Go through each section, assigning them section numbers and and fill in |
| 163 | // the size for sections that aren't incrementally updated. |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 164 | assert(!SectionNumbersAssigned); |
| 165 | SizeT CurSectionNumber = 0; |
| 166 | NullSection->setNumber(CurSectionNumber++); |
| 167 | // The rest of the fields are initialized to 0, and stay that way. |
| 168 | AllSections.push_back(NullSection); |
| 169 | |
| 170 | assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections, |
| 171 | RelTextSections, AllSections); |
| 172 | assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections, |
| 173 | RelDataSections, AllSections); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 174 | for (ELFSection *BSSSection : BSSSections) { |
| 175 | BSSSection->setNumber(CurSectionNumber++); |
| 176 | BSSSection->setNameStrIndex(ShStrTab->getIndex(BSSSection->getName())); |
| 177 | AllSections.push_back(BSSSection); |
| 178 | } |
| 179 | assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RODataSections, |
| 180 | RelRODataSections, AllSections); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 181 | |
| 182 | ShStrTab->setNumber(CurSectionNumber++); |
| 183 | ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName())); |
| 184 | AllSections.push_back(ShStrTab); |
| 185 | |
| 186 | SymTab->setNumber(CurSectionNumber++); |
| 187 | SymTab->setNameStrIndex(ShStrTab->getIndex(SymTab->getName())); |
| 188 | AllSections.push_back(SymTab); |
| 189 | |
| 190 | StrTab->setNumber(CurSectionNumber++); |
| 191 | StrTab->setNameStrIndex(ShStrTab->getIndex(StrTab->getName())); |
| 192 | AllSections.push_back(StrTab); |
| 193 | |
| 194 | SymTab->setLinkNum(StrTab->getNumber()); |
| 195 | SymTab->setInfoNum(SymTab->getNumLocals()); |
| 196 | |
| 197 | assignRelLinkNum(SymTab->getNumber(), RelTextSections); |
| 198 | assignRelLinkNum(SymTab->getNumber(), RelDataSections); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 199 | assignRelLinkNum(SymTab->getNumber(), RelRODataSections); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 200 | SectionNumbersAssigned = true; |
| 201 | } |
| 202 | |
| 203 | Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 204 | Elf64_Off OffsetInFile = Str.tell(); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 205 | Elf64_Xword AlignDiff = Utils::OffsetToAlignment(OffsetInFile, Align); |
| 206 | if (AlignDiff == 0) |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 207 | return OffsetInFile; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 208 | Str.writeZeroPadding(AlignDiff); |
| 209 | OffsetInFile += AlignDiff; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 210 | return OffsetInFile; |
| 211 | } |
| 212 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 213 | void ELFObjectWriter::writeFunctionCode(GlobalString FuncName, bool IsInternal, |
| 214 | Assembler *Asm) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 215 | assert(!SectionNumbersAssigned); |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 216 | TimerMarker T_func(&Ctx, FuncName.toStringOrEmpty()); |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 217 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 218 | ELFTextSection *Section = nullptr; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 219 | ELFRelocationSection *RelSection = nullptr; |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 220 | const bool FunctionSections = getFlags().getFunctionSections(); |
Jan Voung | cb165ca | 2015-02-24 08:53:52 -0800 | [diff] [blame] | 221 | if (TextSections.empty() || FunctionSections) { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 222 | std::string SectionName = ".text"; |
Jan Voung | cb165ca | 2015-02-24 08:53:52 -0800 | [diff] [blame] | 223 | if (FunctionSections) |
| 224 | SectionName += "." + FuncName; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 225 | constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR; |
Jan Voung | e9079cb | 2015-02-25 09:08:44 -0800 | [diff] [blame] | 226 | const Elf64_Xword ShAlign = 1 << Asm->getBundleAlignLog2Bytes(); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 227 | Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags, |
| 228 | ShAlign, 0); |
| 229 | Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign()); |
| 230 | Section->setFileOffset(OffsetInFile); |
| 231 | TextSections.push_back(Section); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 232 | RelSection = createRelocationSection(Section); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 233 | RelTextSections.push_back(RelSection); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 234 | } else { |
| 235 | Section = TextSections[0]; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 236 | RelSection = RelTextSections[0]; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 237 | } |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 238 | const RelocOffsetT OffsetInSection = Section->getCurrentSize(); |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 239 | // Function symbols are set to 0 size in the symbol table, in contrast to |
| 240 | // data symbols which have a proper size. |
John Porto | 56958cb | 2016-01-14 09:18:18 -0800 | [diff] [blame] | 241 | constexpr SizeT SymbolSize = 0; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 242 | uint8_t SymbolType; |
| 243 | uint8_t SymbolBinding; |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 244 | if (IsInternal && !getFlags().getDisableInternal()) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 245 | SymbolType = STT_NOTYPE; |
| 246 | SymbolBinding = STB_LOCAL; |
| 247 | } else { |
| 248 | SymbolType = STT_FUNC; |
| 249 | SymbolBinding = STB_GLOBAL; |
| 250 | } |
| 251 | SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section, |
| 252 | OffsetInSection, SymbolSize); |
| 253 | StrTab->add(FuncName); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 254 | |
Jan Voung | cb165ca | 2015-02-24 08:53:52 -0800 | [diff] [blame] | 255 | // Copy the fixup information from per-function Assembler memory to the |
| 256 | // object writer's memory, for writing later. |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 257 | const auto &Fixups = Asm->fixups(); |
| 258 | if (!Fixups.empty()) { |
| 259 | if (!RelSection->isRela()) { |
| 260 | // This is a non-rela section, so we need to update the instruction stream |
| 261 | // with the relocation addends. |
| 262 | for (const auto *Fixup : Fixups) { |
| 263 | Fixup->emitOffset(Asm); |
| 264 | } |
| 265 | } |
Jim Stichnoth | 3e32400 | 2016-03-08 16:18:40 -0800 | [diff] [blame] | 266 | RelSection->addRelocations(OffsetInSection, Asm->fixups(), SymTab); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 267 | } |
John Porto | 6e8d3fa | 2016-02-04 10:35:20 -0800 | [diff] [blame] | 268 | Section->appendData(Str, Asm->getBufferView()); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 269 | } |
| 270 | |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 271 | namespace { |
| 272 | |
| 273 | ELFObjectWriter::SectionType |
| 274 | classifyGlobalSection(const VariableDeclaration *Var) { |
| 275 | if (Var->getIsConstant()) |
| 276 | return ELFObjectWriter::ROData; |
| 277 | if (Var->hasNonzeroInitializer()) |
| 278 | return ELFObjectWriter::Data; |
| 279 | return ELFObjectWriter::BSS; |
| 280 | } |
| 281 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 282 | // Partition the Vars list by SectionType into VarsBySection. If TranslateOnly |
| 283 | // is non-empty, then only the TranslateOnly variable is kept for emission. |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 284 | void partitionGlobalsBySection(const VariableDeclarationList &Vars, |
Jim Stichnoth | dd6dcfa | 2016-04-18 12:52:09 -0700 | [diff] [blame] | 285 | VariableDeclarationPartition VarsBySection[]) { |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 286 | for (VariableDeclaration *Var : Vars) { |
Jim Stichnoth | dd6dcfa | 2016-04-18 12:52:09 -0700 | [diff] [blame] | 287 | if (getFlags().matchTranslateOnly(Var->getName(), 0)) { |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 288 | size_t Section = classifyGlobalSection(Var); |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 289 | assert(Section < ELFObjectWriter::NumSectionTypes); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 290 | VarsBySection[Section].push_back(Var); |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | } // end of anonymous namespace |
| 296 | |
Jaydeep Patil | 3da9f65 | 2016-11-03 22:54:06 -0700 | [diff] [blame] | 297 | void ELFObjectWriter::writeTargetRODataSection(const std::string &Name, |
| 298 | Elf64_Word ShType, |
| 299 | Elf64_Xword ShFlags, |
| 300 | Elf64_Xword ShAddralign, |
| 301 | Elf64_Xword ShEntsize, |
| 302 | const llvm::StringRef &SecData) { |
| 303 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
| 304 | assert(!SectionNumbersAssigned); |
| 305 | ELFDataSection *Section = createSection<ELFDataSection>( |
| 306 | Name, ShType, ShFlags, ShAddralign, ShEntsize); |
| 307 | Section->setFileOffset(alignFileOffset(ShAddralign)); |
| 308 | Section->appendData(Str, llvm::StringRef(SecData.data(), SecData.size())); |
| 309 | RODataSections.push_back(Section); |
| 310 | } |
| 311 | |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 312 | void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars, |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 313 | FixupKind RelocationKind, |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 314 | const std::string &SectionSuffix, |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 315 | bool IsPIC) { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 316 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 317 | assert(!SectionNumbersAssigned); |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 318 | VariableDeclarationPartition VarsBySection[ELFObjectWriter::NumSectionTypes]; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 319 | for (auto &SectionList : VarsBySection) |
| 320 | SectionList.reserve(Vars.size()); |
Jim Stichnoth | dd6dcfa | 2016-04-18 12:52:09 -0700 | [diff] [blame] | 321 | partitionGlobalsBySection(Vars, VarsBySection); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 322 | size_t I = 0; |
| 323 | for (auto &SectionList : VarsBySection) { |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 324 | writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind, |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 325 | SectionSuffix, IsPIC); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 326 | } |
| 327 | } |
| 328 | |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 329 | namespace { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 330 | std::string MangleSectionName(const char Base[], const std::string &Suffix) { |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 331 | if (Suffix.empty()) |
| 332 | return Base; |
| 333 | return Base + ("." + Suffix); |
| 334 | } |
| 335 | } // end of anonymous namespace |
| 336 | |
| 337 | // TODO(jvoung): Handle fdata-sections. |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 338 | void ELFObjectWriter::writeDataOfType(SectionType ST, |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 339 | const VariableDeclarationPartition &Vars, |
John Porto | 8b1a705 | 2015-06-17 13:20:08 -0700 | [diff] [blame] | 340 | FixupKind RelocationKind, |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 341 | const std::string &SectionSuffix, |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 342 | bool IsPIC) { |
Jan Voung | 77973cc | 2015-02-03 12:48:38 -0800 | [diff] [blame] | 343 | if (Vars.empty()) |
| 344 | return; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 345 | ELFDataSection *Section; |
| 346 | ELFRelocationSection *RelSection; |
Jan Voung | 77973cc | 2015-02-03 12:48:38 -0800 | [diff] [blame] | 347 | Elf64_Xword ShAddralign = 1; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 348 | for (VariableDeclaration *Var : Vars) { |
| 349 | Elf64_Xword Align = Var->getAlignment(); |
| 350 | ShAddralign = std::max(ShAddralign, Align); |
| 351 | } |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 352 | constexpr Elf64_Xword ShEntsize = 0; // non-uniform data element size. |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 353 | // Lift this out, so it can be re-used if we do fdata-sections? |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 354 | switch (ST) { |
| 355 | case ROData: { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 356 | const std::string SectionName = |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 357 | MangleSectionName(IsPIC ? ".data.rel.ro" : ".rodata", SectionSuffix); |
Jim Stichnoth | caeaa27 | 2016-01-10 12:53:44 -0800 | [diff] [blame] | 358 | const Elf64_Xword ShFlags = IsPIC ? (SHF_ALLOC | SHF_WRITE) : SHF_ALLOC; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 359 | Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags, |
| 360 | ShAddralign, ShEntsize); |
| 361 | Section->setFileOffset(alignFileOffset(ShAddralign)); |
| 362 | RODataSections.push_back(Section); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 363 | RelSection = createRelocationSection(Section); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 364 | RelRODataSections.push_back(RelSection); |
| 365 | break; |
| 366 | } |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 367 | case Data: { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 368 | const std::string SectionName = MangleSectionName(".data", SectionSuffix); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 369 | constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 370 | Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags, |
| 371 | ShAddralign, ShEntsize); |
| 372 | Section->setFileOffset(alignFileOffset(ShAddralign)); |
| 373 | DataSections.push_back(Section); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 374 | RelSection = createRelocationSection(Section); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 375 | RelDataSections.push_back(RelSection); |
| 376 | break; |
| 377 | } |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 378 | case BSS: { |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 379 | const std::string SectionName = MangleSectionName(".bss", SectionSuffix); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 380 | constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 381 | Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags, |
| 382 | ShAddralign, ShEntsize); |
| 383 | Section->setFileOffset(alignFileOffset(ShAddralign)); |
| 384 | BSSSections.push_back(Section); |
| 385 | break; |
| 386 | } |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 387 | case NumSectionTypes: |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 388 | llvm::report_fatal_error("Unknown SectionType"); |
| 389 | break; |
| 390 | } |
| 391 | |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 392 | constexpr uint8_t SymbolType = STT_OBJECT; |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 393 | for (VariableDeclaration *Var : Vars) { |
Jan Voung | 77973cc | 2015-02-03 12:48:38 -0800 | [diff] [blame] | 394 | // If the variable declaration does not have an initializer, its symtab |
| 395 | // entry will be created separately. |
| 396 | if (!Var->hasInitializer()) |
| 397 | continue; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 398 | constexpr Elf64_Xword MinAlign = 1; |
John Porto | 267f2bf | 2016-03-24 06:11:29 -0700 | [diff] [blame] | 399 | const auto Align = std::max<Elf64_Xword>(MinAlign, Var->getAlignment()); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 400 | Section->padToAlignment(Str, Align); |
| 401 | SizeT SymbolSize = Var->getNumBytes(); |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 402 | bool IsExternal = Var->isExternal() || getFlags().getDisableInternal(); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 403 | const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 404 | GlobalString Name = Var->getName(); |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 405 | SymTab->createDefinedSym(Name, SymbolType, SymbolBinding, Section, |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 406 | Section->getCurrentSize(), SymbolSize); |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 407 | StrTab->add(Name); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 408 | if (!Var->hasNonzeroInitializer()) { |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 409 | assert(ST == BSS || ST == ROData); |
| 410 | if (ST == ROData) |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 411 | Section->appendZeros(Str, SymbolSize); |
| 412 | else |
| 413 | Section->setSize(Section->getCurrentSize() + SymbolSize); |
| 414 | } else { |
JF Bastien | ae6e12c | 2015-01-31 10:13:25 -0800 | [diff] [blame] | 415 | assert(ST != BSS); |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 416 | for (const auto *Init : Var->getInitializers()) { |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 417 | switch (Init->getKind()) { |
| 418 | case VariableDeclaration::Initializer::DataInitializerKind: { |
Qining Lu | 7cd5351 | 2015-06-26 09:36:00 -0700 | [diff] [blame] | 419 | const auto &Data = |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 420 | llvm::cast<VariableDeclaration::DataInitializer>(Init) |
Jim Stichnoth | 20b71f5 | 2015-06-24 15:52:24 -0700 | [diff] [blame] | 421 | ->getContents(); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 422 | Section->appendData(Str, llvm::StringRef(Data.data(), Data.size())); |
| 423 | break; |
| 424 | } |
| 425 | case VariableDeclaration::Initializer::ZeroInitializerKind: |
| 426 | Section->appendZeros(Str, Init->getNumBytes()); |
| 427 | break; |
| 428 | case VariableDeclaration::Initializer::RelocInitializerKind: { |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 429 | const auto *Reloc = |
John Porto | a78e4ba | 2016-03-15 09:28:04 -0700 | [diff] [blame] | 430 | llvm::cast<VariableDeclaration::RelocInitializer>(Init); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 431 | AssemblerFixup NewFixup; |
| 432 | NewFixup.set_position(Section->getCurrentSize()); |
John Porto | dc61925 | 2016-02-10 15:57:16 -0800 | [diff] [blame] | 433 | NewFixup.set_kind(Reloc->hasFixup() ? Reloc->getFixup() |
| 434 | : RelocationKind); |
| 435 | assert(NewFixup.kind() != llvm::ELF::R_ARM_NONE); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 436 | NewFixup.set_value(Ctx.getConstantSym( |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 437 | Reloc->getOffset(), Reloc->getDeclaration()->getName())); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 438 | RelSection->addRelocation(NewFixup); |
| 439 | Section->appendRelocationOffset(Str, RelSection->isRela(), |
| 440 | Reloc->getOffset()); |
| 441 | break; |
| 442 | } |
| 443 | } |
| 444 | } |
| 445 | } |
| 446 | } |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 447 | } |
| 448 | |
| 449 | void ELFObjectWriter::writeInitialELFHeader() { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 450 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 451 | assert(!SectionNumbersAssigned); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 452 | constexpr Elf64_Off DummySHOffset = 0; |
| 453 | constexpr SizeT DummySHStrIndex = 0; |
| 454 | constexpr SizeT DummyNumSections = 0; |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 455 | if (ELF64) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 456 | writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex, |
| 457 | DummyNumSections); |
| 458 | } else { |
| 459 | writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex, |
| 460 | DummyNumSections); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | template <bool IsELF64> |
Jan Voung | a601cc5 | 2014-12-03 15:51:22 -0800 | [diff] [blame] | 465 | void ELFObjectWriter::writeELFHeaderInternal(Elf64_Off SectionHeaderOffset, |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 466 | SizeT SectHeaderStrIndex, |
| 467 | SizeT NumSections) { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 468 | // Write the e_ident: magic number, class, etc. The e_ident is byte order and |
| 469 | // ELF class independent. |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 470 | Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic))); |
| 471 | Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32); |
| 472 | Str.write8(ELFDATA2LSB); |
| 473 | Str.write8(EV_CURRENT); |
| 474 | Str.write8(ELFOSABI_NONE); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 475 | constexpr uint8_t ELF_ABIVersion = 0; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 476 | Str.write8(ELF_ABIVersion); |
| 477 | Str.writeZeroPadding(EI_NIDENT - EI_PAD); |
| 478 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 479 | // TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc: |
| 480 | // https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html e_shnum should |
| 481 | // be 0 and then actual number of sections is stored in the sh_size member of |
| 482 | // the 0th section. |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 483 | assert(NumSections < SHN_LORESERVE); |
| 484 | assert(SectHeaderStrIndex < SHN_LORESERVE); |
| 485 | |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 486 | const TargetArch Arch = getFlags().getTargetArch(); |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 487 | // Write the rest of the file header, which does depend on byte order and ELF |
| 488 | // class. |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 489 | Str.writeLE16(ET_REL); // e_type |
| 490 | Str.writeLE16(getELFMachine(getFlags().getTargetArch())); // e_machine |
| 491 | Str.writeELFWord<IsELF64>(1); // e_version |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 492 | // Since this is for a relocatable object, there is no entry point, and no |
| 493 | // program headers. |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 494 | Str.writeAddrOrOffset<IsELF64>(0); // e_entry |
| 495 | Str.writeAddrOrOffset<IsELF64>(0); // e_phoff |
| 496 | Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 497 | Str.writeELFWord<IsELF64>(getELFFlags(Arch)); // e_flags |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 498 | Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize |
| 499 | static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52, |
| 500 | "Elf_Ehdr sizes cannot be derived from sizeof"); |
| 501 | Str.writeLE16(0); // e_phentsize |
| 502 | Str.writeLE16(0); // e_phnum |
| 503 | Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr) |
| 504 | : sizeof(Elf32_Shdr)); // e_shentsize |
| 505 | static_assert(sizeof(Elf64_Shdr) == 64 && sizeof(Elf32_Shdr) == 40, |
| 506 | "Elf_Shdr sizes cannot be derived from sizeof"); |
| 507 | Str.writeLE16(static_cast<Elf64_Half>(NumSections)); // e_shnum |
| 508 | Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx |
| 509 | } |
| 510 | |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 511 | template <typename ConstType> void ELFObjectWriter::writeConstantPool(Type Ty) { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 512 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 513 | ConstantList Pool = Ctx.getConstantPool(Ty); |
| 514 | if (Pool.empty()) { |
| 515 | return; |
| 516 | } |
| 517 | SizeT Align = typeAlignInBytes(Ty); |
| 518 | size_t EntSize = typeWidthInBytes(Ty); |
| 519 | char Buf[20]; |
| 520 | SizeT WriteAmt = std::min(EntSize, llvm::array_lengthof(Buf)); |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 521 | // Check that we write the full PrimType. |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 522 | assert(WriteAmt == EntSize); |
| 523 | // Assume that writing WriteAmt bytes at a time allows us to avoid aligning |
| 524 | // between entries. |
| 525 | assert(WriteAmt % Align == 0); |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 526 | constexpr Elf64_Xword ShFlags = SHF_ALLOC | SHF_MERGE; |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 527 | std::string SecBuffer; |
| 528 | llvm::raw_string_ostream SecStrBuf(SecBuffer); |
| 529 | SecStrBuf << ".rodata.cst" << WriteAmt; |
| 530 | ELFDataSection *Section = createSection<ELFDataSection>( |
| 531 | SecStrBuf.str(), SHT_PROGBITS, ShFlags, Align, WriteAmt); |
Jan Voung | 72984d8 | 2015-01-29 14:42:38 -0800 | [diff] [blame] | 532 | RODataSections.push_back(Section); |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 533 | SizeT OffsetInSection = 0; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 534 | // The symbol table entry doesn't need to know the defined symbol's size |
| 535 | // since this is in a section with a fixed Entry Size. |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 536 | constexpr SizeT SymbolSize = 0; |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 537 | Section->setFileOffset(alignFileOffset(Align)); |
| 538 | |
| 539 | // Write the data. |
| 540 | for (Constant *C : Pool) { |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 541 | if (!C->getShouldBePooled()) |
| 542 | continue; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 543 | auto *Const = llvm::cast<ConstType>(C); |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 544 | GlobalString SymName = Const->getLabelName(); |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 545 | SymTab->createDefinedSym(SymName, STT_NOTYPE, STB_LOCAL, Section, |
| 546 | OffsetInSection, SymbolSize); |
| 547 | StrTab->add(SymName); |
| 548 | typename ConstType::PrimType Value = Const->getValue(); |
| 549 | memcpy(Buf, &Value, WriteAmt); |
| 550 | Str.writeBytes(llvm::StringRef(Buf, WriteAmt)); |
| 551 | OffsetInSection += WriteAmt; |
| 552 | } |
| 553 | Section->setSize(OffsetInSection); |
| 554 | } |
| 555 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 556 | // Instantiate known needed versions of the template, since we are defining the |
| 557 | // function in the .cpp file instead of the .h file. We may need to instantiate |
| 558 | // constant pools for integers as well if we do constant-pooling of large |
| 559 | // integers to remove them from the instruction stream (fewer bytes controlled |
| 560 | // by an attacker). |
Jan Voung | 91a3e2c | 2015-01-09 13:01:42 -0800 | [diff] [blame] | 561 | template void ELFObjectWriter::writeConstantPool<ConstantFloat>(Type Ty); |
| 562 | |
| 563 | template void ELFObjectWriter::writeConstantPool<ConstantDouble>(Type Ty); |
| 564 | |
Qining Lu | 253dc8a | 2015-06-22 10:10:23 -0700 | [diff] [blame] | 565 | template void ELFObjectWriter::writeConstantPool<ConstantInteger32>(Type Ty); |
| 566 | |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 567 | void ELFObjectWriter::writeAllRelocationSections() { |
| 568 | writeRelocationSections(RelTextSections); |
| 569 | writeRelocationSections(RelDataSections); |
| 570 | writeRelocationSections(RelRODataSections); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 571 | } |
| 572 | |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 573 | void ELFObjectWriter::writeJumpTable(const JumpTableData &JT, |
Jim Stichnoth | 8ff4b28 | 2016-01-04 15:39:06 -0800 | [diff] [blame] | 574 | FixupKind RelocationKind, bool IsPIC) { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 575 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 576 | ELFDataSection *Section; |
| 577 | ELFRelocationSection *RelSection; |
| 578 | const Elf64_Xword PointerSize = typeWidthInBytes(getPointerType()); |
| 579 | const Elf64_Xword ShAddralign = PointerSize; |
| 580 | const Elf64_Xword ShEntsize = PointerSize; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 581 | const std::string SectionName = MangleSectionName( |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 582 | IsPIC ? ".data.rel.ro" : ".rodata", JT.getSectionName()); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 583 | Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, SHF_ALLOC, |
| 584 | ShAddralign, ShEntsize); |
| 585 | Section->setFileOffset(alignFileOffset(ShAddralign)); |
| 586 | RODataSections.push_back(Section); |
| 587 | RelSection = createRelocationSection(Section); |
| 588 | RelRODataSections.push_back(RelSection); |
| 589 | |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 590 | constexpr uint8_t SymbolType = STT_OBJECT; |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 591 | Section->padToAlignment(Str, PointerSize); |
Karl Schimpf | d469994 | 2016-04-02 09:55:31 -0700 | [diff] [blame] | 592 | const bool IsExternal = getFlags().getDisableInternal(); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 593 | const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL; |
John Porto | 0307721 | 2016-04-05 06:30:21 -0700 | [diff] [blame] | 594 | const auto JumpTableName = JT.getName(); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 595 | SymTab->createDefinedSym(JumpTableName, SymbolType, SymbolBinding, Section, |
| 596 | Section->getCurrentSize(), PointerSize); |
| 597 | StrTab->add(JumpTableName); |
| 598 | |
| 599 | for (intptr_t TargetOffset : JT.getTargetOffsets()) { |
| 600 | AssemblerFixup NewFixup; |
| 601 | NewFixup.set_position(Section->getCurrentSize()); |
| 602 | NewFixup.set_kind(RelocationKind); |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 603 | NewFixup.set_value(Ctx.getConstantSym(TargetOffset, JT.getFunctionName())); |
Andrew Scull | 86df4e9 | 2015-07-30 13:54:44 -0700 | [diff] [blame] | 604 | RelSection->addRelocation(NewFixup); |
| 605 | Section->appendRelocationOffset(Str, RelSection->isRela(), TargetOffset); |
| 606 | } |
| 607 | } |
| 608 | |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 609 | void ELFObjectWriter::setUndefinedSyms(const ConstantList &UndefSyms) { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 610 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 611 | for (const Constant *S : UndefSyms) { |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 612 | const auto *Sym = llvm::cast<ConstantRelocatable>(S); |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 613 | GlobalString Name = Sym->getName(); |
| 614 | assert(Name.hasStdString()); |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 615 | assert(Sym->getOffset() == 0); |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 616 | SymTab->noteUndefinedSym(Name, NullSection); |
| 617 | StrTab->add(Name); |
| 618 | } |
| 619 | } |
| 620 | |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 621 | void ELFObjectWriter::writeRelocationSections(RelSectionList &RelSections) { |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 622 | for (ELFRelocationSection *RelSec : RelSections) { |
| 623 | Elf64_Off Offset = alignFileOffset(RelSec->getSectionAlign()); |
| 624 | RelSec->setFileOffset(Offset); |
Jan Voung | 261cae3 | 2015-02-01 10:31:03 -0800 | [diff] [blame] | 625 | RelSec->setSize(RelSec->getSectionDataSize()); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 626 | if (ELF64) { |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 627 | RelSec->writeData<true>(Str, SymTab); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 628 | } else { |
Jim Stichnoth | 98ba006 | 2016-03-07 09:26:22 -0800 | [diff] [blame] | 629 | RelSec->writeData<false>(Str, SymTab); |
Jan Voung | ec27073 | 2015-01-12 17:00:22 -0800 | [diff] [blame] | 630 | } |
| 631 | } |
| 632 | } |
| 633 | |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 634 | void ELFObjectWriter::writeNonUserSections() { |
Karl Schimpf | b6e9b89 | 2016-03-08 12:27:12 -0800 | [diff] [blame] | 635 | TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); |
| 636 | |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 637 | // Write out the shstrtab now that all sections are known. |
| 638 | ShStrTab->doLayout(); |
| 639 | ShStrTab->setSize(ShStrTab->getSectionDataSize()); |
| 640 | Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign()); |
| 641 | ShStrTab->setFileOffset(ShStrTabOffset); |
| 642 | Str.writeBytes(ShStrTab->getSectionData()); |
| 643 | |
| 644 | SectionList AllSections; |
| 645 | assignSectionNumbersInfo(AllSections); |
| 646 | |
| 647 | // Finalize the regular StrTab and fix up references in the SymTab. |
| 648 | StrTab->doLayout(); |
| 649 | StrTab->setSize(StrTab->getSectionDataSize()); |
| 650 | |
| 651 | SymTab->updateIndices(StrTab); |
| 652 | |
| 653 | Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign()); |
| 654 | SymTab->setFileOffset(SymTabOffset); |
| 655 | SymTab->setSize(SymTab->getSectionDataSize()); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 656 | SymTab->writeData(Str, ELF64); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 657 | |
| 658 | Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign()); |
| 659 | StrTab->setFileOffset(StrTabOffset); |
| 660 | Str.writeBytes(StrTab->getSectionData()); |
| 661 | |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 662 | writeAllRelocationSections(); |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 663 | |
| 664 | // Write out the section headers. |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 665 | const size_t ShdrAlign = ELF64 ? 8 : 4; |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 666 | Elf64_Off ShOffset = alignFileOffset(ShdrAlign); |
| 667 | for (const auto S : AllSections) { |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 668 | if (ELF64) |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 669 | S->writeHeader<true>(Str); |
| 670 | else |
| 671 | S->writeHeader<false>(Str); |
| 672 | } |
| 673 | |
| 674 | // Finally write the updated ELF header w/ the correct number of sections. |
| 675 | Str.seek(0); |
Jan Voung | 1f47ad0 | 2015-03-20 15:01:26 -0700 | [diff] [blame] | 676 | if (ELF64) { |
Jan Voung | 08c3bcd | 2014-12-01 17:55:16 -0800 | [diff] [blame] | 677 | writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(), |
| 678 | AllSections.size()); |
| 679 | } else { |
| 680 | writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(), |
| 681 | AllSections.size()); |
| 682 | } |
| 683 | } |
| 684 | |
| 685 | } // end of namespace Ice |