OLD | NEW |
(Empty) | |
| 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 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // This file defines the writer for ELF relocatable object files. |
| 11 // |
| 12 //===----------------------------------------------------------------------===// |
| 13 |
| 14 #include "IceDefs.h" |
| 15 #include "IceELFObjectWriter.h" |
| 16 #include "IceELFSection.h" |
| 17 #include "IceELFStreamer.h" |
| 18 #include "IceGlobalContext.h" |
| 19 #include "IceGlobalInits.h" |
| 20 |
| 21 using namespace llvm::ELF; |
| 22 |
| 23 namespace Ice { |
| 24 |
| 25 namespace { |
| 26 |
| 27 struct { |
| 28 bool IsELF64; |
| 29 uint16_t ELFMachine; |
| 30 uint32_t ELFFlags; |
| 31 } ELFTargetInfo[] = { |
| 32 #define X(tag, str, is_elf64, e_machine, e_flags) \ |
| 33 { is_elf64, e_machine, e_flags } \ |
| 34 , |
| 35 TARGETARCH_TABLE |
| 36 #undef X |
| 37 }; |
| 38 |
| 39 bool isELF64(TargetArch Arch) { |
| 40 if (Arch < TargetArch_NUM) |
| 41 return ELFTargetInfo[Arch].IsELF64; |
| 42 llvm_unreachable("Invalid target arch for isELF64"); |
| 43 return false; |
| 44 } |
| 45 |
| 46 uint16_t getELFMachine(TargetArch Arch) { |
| 47 if (Arch < TargetArch_NUM) |
| 48 return ELFTargetInfo[Arch].ELFMachine; |
| 49 llvm_unreachable("Invalid target arch for getELFMachine"); |
| 50 return EM_NONE; |
| 51 } |
| 52 |
| 53 uint32_t getELFFlags(TargetArch Arch) { |
| 54 if (Arch < TargetArch_NUM) |
| 55 return ELFTargetInfo[Arch].ELFFlags; |
| 56 llvm_unreachable("Invalid target arch for getELFFlags"); |
| 57 return 0; |
| 58 } |
| 59 |
| 60 } // end of anonymous namespace |
| 61 |
| 62 ELFObjectWriter::ELFObjectWriter(GlobalContext &Ctx, ELFStreamer &Out) |
| 63 : Ctx(Ctx), Str(Out), SectionNumbersAssigned(false) { |
| 64 // Create the special bookkeeping sections now. |
| 65 const IceString NullSectionName(""); |
| 66 NullSection = new (Ctx.allocate<ELFSection>()) |
| 67 ELFSection(NullSectionName, SHT_NULL, 0, 0, 0); |
| 68 |
| 69 const IceString ShStrTabName(".shstrtab"); |
| 70 ShStrTab = new (Ctx.allocate<ELFStringTableSection>()) |
| 71 ELFStringTableSection(ShStrTabName, SHT_STRTAB, 0, 1, 0); |
| 72 ShStrTab->add(ShStrTabName); |
| 73 |
| 74 const IceString SymTabName(".symtab"); |
| 75 bool IsELF64 = isELF64(Ctx.getTargetArch()); |
| 76 const Elf64_Xword SymTabAlign = IsELF64 ? 8 : 4; |
| 77 const Elf64_Xword SymTabEntSize = |
| 78 IsELF64 ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym); |
| 79 static_assert(sizeof(Elf64_Sym) == 24 && sizeof(Elf32_Sym) == 16, |
| 80 "Elf_Sym sizes cannot be derived from sizeof"); |
| 81 SymTab = createSection<ELFSymbolTableSection>(SymTabName, SHT_SYMTAB, 0, |
| 82 SymTabAlign, SymTabEntSize); |
| 83 // The first entry in the symbol table should be a NULL entry. |
| 84 const IceString NullSymName(""); |
| 85 SymTab->createDefinedSym(NullSymName, STT_NOTYPE, STB_LOCAL, NullSection, 0, |
| 86 0); |
| 87 |
| 88 const IceString StrTabName(".strtab"); |
| 89 StrTab = |
| 90 createSection<ELFStringTableSection>(StrTabName, SHT_STRTAB, 0, 1, 0); |
| 91 } |
| 92 |
| 93 template <typename T> |
| 94 T *ELFObjectWriter::createSection(const IceString &Name, Elf64_Word ShType, |
| 95 Elf64_Xword ShFlags, Elf64_Xword ShAddralign, |
| 96 Elf64_Xword ShEntsize) { |
| 97 assert(!SectionNumbersAssigned); |
| 98 T *NewSection = |
| 99 new (Ctx.allocate<T>()) T(Name, ShType, ShFlags, ShAddralign, ShEntsize); |
| 100 ShStrTab->add(Name); |
| 101 return NewSection; |
| 102 } |
| 103 |
| 104 template <typename UserSectionList> |
| 105 void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, |
| 106 UserSectionList &UserSections, |
| 107 RelSectionList &RelSections, |
| 108 SectionList &AllSections) { |
| 109 RelSectionList::iterator RelIt = RelSections.begin(); |
| 110 RelSectionList::iterator RelE = RelSections.end(); |
| 111 for (ELFSection *UserSection : UserSections) { |
| 112 UserSection->setNumber(CurSectionNumber++); |
| 113 UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName())); |
| 114 AllSections.push_back(UserSection); |
| 115 if (RelIt != RelE) { |
| 116 ELFRelocationSectionBase *RelSection = *RelIt; |
| 117 if (RelSection->getRelatedSection() == UserSection) { |
| 118 RelSection->setInfoNum(UserSection->getNumber()); |
| 119 RelSection->setNumber(CurSectionNumber++); |
| 120 RelSection->setNameStrIndex(ShStrTab->getIndex(RelSection->getName())); |
| 121 AllSections.push_back(RelSection); |
| 122 ++RelIt; |
| 123 } |
| 124 } |
| 125 } |
| 126 // Should finish with UserIt at the same time as RelIt. |
| 127 assert(RelIt == RelE); |
| 128 return; |
| 129 } |
| 130 |
| 131 void ELFObjectWriter::assignRelLinkNum(SizeT SymTabNumber, |
| 132 RelSectionList &RelSections) { |
| 133 for (ELFRelocationSectionBase *S : RelSections) { |
| 134 S->setLinkNum(SymTabNumber); |
| 135 } |
| 136 } |
| 137 |
| 138 void ELFObjectWriter::assignSectionNumbersInfo(SectionList &AllSections) { |
| 139 // Go through each section, assigning them section numbers and |
| 140 // and fill in the size for sections that aren't incrementally updated. |
| 141 assert(!SectionNumbersAssigned); |
| 142 SizeT CurSectionNumber = 0; |
| 143 NullSection->setNumber(CurSectionNumber++); |
| 144 // The rest of the fields are initialized to 0, and stay that way. |
| 145 AllSections.push_back(NullSection); |
| 146 |
| 147 assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections, |
| 148 RelTextSections, AllSections); |
| 149 assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections, |
| 150 RelDataSections, AllSections); |
| 151 assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, RoDataSections, |
| 152 RelRoDataSections, AllSections); |
| 153 |
| 154 ShStrTab->setNumber(CurSectionNumber++); |
| 155 ShStrTab->setNameStrIndex(ShStrTab->getIndex(ShStrTab->getName())); |
| 156 AllSections.push_back(ShStrTab); |
| 157 |
| 158 SymTab->setNumber(CurSectionNumber++); |
| 159 SymTab->setNameStrIndex(ShStrTab->getIndex(SymTab->getName())); |
| 160 AllSections.push_back(SymTab); |
| 161 |
| 162 StrTab->setNumber(CurSectionNumber++); |
| 163 StrTab->setNameStrIndex(ShStrTab->getIndex(StrTab->getName())); |
| 164 AllSections.push_back(StrTab); |
| 165 |
| 166 SymTab->setLinkNum(StrTab->getNumber()); |
| 167 SymTab->setInfoNum(SymTab->getNumLocals()); |
| 168 |
| 169 assignRelLinkNum(SymTab->getNumber(), RelTextSections); |
| 170 assignRelLinkNum(SymTab->getNumber(), RelDataSections); |
| 171 assignRelLinkNum(SymTab->getNumber(), RelRoDataSections); |
| 172 SectionNumbersAssigned = true; |
| 173 } |
| 174 |
| 175 Elf64_Off ELFObjectWriter::alignFileOffset(Elf64_Xword Align) { |
| 176 assert(llvm::isPowerOf2_32(Align)); |
| 177 Elf64_Off OffsetInFile = Str.tell(); |
| 178 Elf64_Xword Mod = OffsetInFile & (Align - 1); |
| 179 if (Mod == 0) |
| 180 return OffsetInFile; |
| 181 Elf64_Xword AlignDiff = Align - Mod; |
| 182 Str.writeZeroPadding(AlignDiff); |
| 183 OffsetInFile += AlignDiff; |
| 184 assert((OffsetInFile & (Align - 1)) == 0); |
| 185 return OffsetInFile; |
| 186 } |
| 187 |
| 188 void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, |
| 189 bool IsInternal, |
| 190 const llvm::StringRef Data) { |
| 191 assert(!SectionNumbersAssigned); |
| 192 // TODO(jvoung): handle ffunction-sections. |
| 193 IceString SectionName = ".text"; |
| 194 ELFTextSection *Section = nullptr; |
| 195 if (TextSections.size() == 0) { |
| 196 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR; |
| 197 // TODO(jvoung): Should be bundle size. Grab it from that target? |
| 198 const Elf64_Xword ShAlign = 32; |
| 199 Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags, |
| 200 ShAlign, 0); |
| 201 Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign()); |
| 202 Section->setFileOffset(OffsetInFile); |
| 203 TextSections.push_back(Section); |
| 204 } else { |
| 205 Section = TextSections[0]; |
| 206 } |
| 207 RelocOffsetT OffsetInSection = Section->getCurrentSize(); |
| 208 // Function symbols are set to 0 size in the symbol table, |
| 209 // in contrast to data symbols which have a proper size. |
| 210 SizeT SymbolSize = 0; |
| 211 Section->appendData(Str, Data); |
| 212 uint8_t SymbolType; |
| 213 uint8_t SymbolBinding; |
| 214 if (IsInternal) { |
| 215 SymbolType = STT_NOTYPE; |
| 216 SymbolBinding = STB_LOCAL; |
| 217 } else { |
| 218 SymbolType = STT_FUNC; |
| 219 SymbolBinding = STB_GLOBAL; |
| 220 } |
| 221 SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section, |
| 222 OffsetInSection, SymbolSize); |
| 223 StrTab->add(FuncName); |
| 224 } |
| 225 |
| 226 void ELFObjectWriter::writeDataInitializer(const IceString &VarName, |
| 227 const llvm::StringRef Data) { |
| 228 assert(!SectionNumbersAssigned); |
| 229 (void)Data; |
| 230 llvm_unreachable("TODO"); |
| 231 StrTab->add(VarName); |
| 232 } |
| 233 |
| 234 void ELFObjectWriter::writeInitialELFHeader() { |
| 235 assert(!SectionNumbersAssigned); |
| 236 const size_t DummySHOffset = 0; |
| 237 const SizeT DummySHStrIndex = 0; |
| 238 const SizeT DummyNumSections = 0; |
| 239 if (isELF64(Ctx.getTargetArch())) { |
| 240 writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex, |
| 241 DummyNumSections); |
| 242 } else { |
| 243 writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex, |
| 244 DummyNumSections); |
| 245 } |
| 246 } |
| 247 |
| 248 template <bool IsELF64> |
| 249 void ELFObjectWriter::writeELFHeaderInternal(size_t SectionHeaderOffset, |
| 250 SizeT SectHeaderStrIndex, |
| 251 SizeT NumSections) { |
| 252 // Write the e_ident: magic number, class, etc. |
| 253 // The e_ident is byte order and ELF class independent. |
| 254 Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic))); |
| 255 Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32); |
| 256 Str.write8(ELFDATA2LSB); |
| 257 Str.write8(EV_CURRENT); |
| 258 Str.write8(ELFOSABI_NONE); |
| 259 const uint8_t ELF_ABIVersion = 0; |
| 260 Str.write8(ELF_ABIVersion); |
| 261 Str.writeZeroPadding(EI_NIDENT - EI_PAD); |
| 262 |
| 263 // TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc: |
| 264 // https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html |
| 265 // e_shnum should be 0 and then actual number of sections is |
| 266 // stored in the sh_size member of the 0th section. |
| 267 assert(NumSections < SHN_LORESERVE); |
| 268 assert(SectHeaderStrIndex < SHN_LORESERVE); |
| 269 |
| 270 // Write the rest of the file header, which does depend on byte order |
| 271 // and ELF class. |
| 272 Str.writeLE16(ET_REL); // e_type |
| 273 Str.writeLE16(getELFMachine(Ctx.getTargetArch())); // e_machine |
| 274 Str.writeELFWord<IsELF64>(1); // e_version |
| 275 // Since this is for a relocatable object, there is no entry point, |
| 276 // and no program headers. |
| 277 Str.writeAddrOrOffset<IsELF64>(0); // e_entry |
| 278 Str.writeAddrOrOffset<IsELF64>(0); // e_phoff |
| 279 Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff |
| 280 Str.writeELFWord<IsELF64>(getELFFlags(Ctx.getTargetArch())); // e_flags |
| 281 Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize |
| 282 static_assert(sizeof(Elf64_Ehdr) == 64 && sizeof(Elf32_Ehdr) == 52, |
| 283 "Elf_Ehdr sizes cannot be derived from sizeof"); |
| 284 Str.writeLE16(0); // e_phentsize |
| 285 Str.writeLE16(0); // e_phnum |
| 286 Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr) |
| 287 : sizeof(Elf32_Shdr)); // e_shentsize |
| 288 static_assert(sizeof(Elf64_Shdr) == 64 && sizeof(Elf32_Shdr) == 40, |
| 289 "Elf_Shdr sizes cannot be derived from sizeof"); |
| 290 Str.writeLE16(static_cast<Elf64_Half>(NumSections)); // e_shnum |
| 291 Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx |
| 292 } |
| 293 |
| 294 void ELFObjectWriter::writeNonUserSections() { |
| 295 bool IsELF64 = isELF64(Ctx.getTargetArch()); |
| 296 |
| 297 // Write out the shstrtab now that all sections are known. |
| 298 ShStrTab->doLayout(); |
| 299 ShStrTab->setSize(ShStrTab->getSectionDataSize()); |
| 300 Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign()); |
| 301 ShStrTab->setFileOffset(ShStrTabOffset); |
| 302 Str.writeBytes(ShStrTab->getSectionData()); |
| 303 |
| 304 SectionList AllSections; |
| 305 assignSectionNumbersInfo(AllSections); |
| 306 |
| 307 // Finalize the regular StrTab and fix up references in the SymTab. |
| 308 StrTab->doLayout(); |
| 309 StrTab->setSize(StrTab->getSectionDataSize()); |
| 310 |
| 311 SymTab->updateIndices(StrTab); |
| 312 |
| 313 Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign()); |
| 314 SymTab->setFileOffset(SymTabOffset); |
| 315 SymTab->setSize(SymTab->getSectionDataSize()); |
| 316 SymTab->writeData(Str, IsELF64); |
| 317 |
| 318 Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign()); |
| 319 StrTab->setFileOffset(StrTabOffset); |
| 320 Str.writeBytes(StrTab->getSectionData()); |
| 321 |
| 322 // TODO: Write out the relocation sections. |
| 323 // May also be able to seek around the file and resolve function calls |
| 324 // that are for functions within the same section. |
| 325 |
| 326 // Write out the section headers. |
| 327 const size_t ShdrAlign = IsELF64 ? 8 : 4; |
| 328 Elf64_Off ShOffset = alignFileOffset(ShdrAlign); |
| 329 for (const auto S : AllSections) { |
| 330 if (IsELF64) |
| 331 S->writeHeader<true>(Str); |
| 332 else |
| 333 S->writeHeader<false>(Str); |
| 334 } |
| 335 |
| 336 // Finally write the updated ELF header w/ the correct number of sections. |
| 337 Str.seek(0); |
| 338 if (IsELF64) { |
| 339 writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(), |
| 340 AllSections.size()); |
| 341 } else { |
| 342 writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(), |
| 343 AllSections.size()); |
| 344 } |
| 345 } |
| 346 |
| 347 } // end of namespace Ice |
OLD | NEW |