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