Chromium Code Reviews| 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); | |
|
Jim Stichnoth
2014/11/21 21:32:22
Can you just directly use Arch as the index?
jvoung (off chromium)
2014/11/24 21:35:46
Done.
| |
| 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 the special bookkeeping sections now. | |
| 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); | |
|
Jim Stichnoth
2014/11/21 21:32:22
Probably want to confirm that SymTabAlign and size
jvoung (off chromium)
2014/11/24 21:35:46
Hmm, llvm instances where they use sizeof(Elf_Sym)
Jim Stichnoth
2014/12/01 22:41:06
Cool, static_assert sounds good.
| |
| 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 sh_type, | |
|
Jim Stichnoth
2014/11/21 21:32:22
Capitalize arg names
jvoung (off chromium)
2014/11/24 21:35:46
Done.
| |
| 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 template <typename UserSectionList> | |
| 106 void ELFObjectWriter::assignRelSectionNumInPairs(SizeT &CurSectionNumber, | |
| 107 UserSectionList &UserSections, | |
| 108 RelSectionList &RelSections, | |
| 109 SectionList &AllSections) { | |
| 110 auto UserIt = UserSections.begin(); | |
|
Jim Stichnoth
2014/11/21 21:32:22
Can UserIt/UserE be subsumed into a range-based fo
jvoung (off chromium)
2014/11/24 21:35:45
Done.
| |
| 111 auto UserE = UserSections.end(); | |
| 112 auto RelIt = RelSections.begin(); | |
| 113 auto RelE = RelSections.end(); | |
| 114 while (UserIt != UserE) { | |
| 115 ELFSection *UserSection = *UserIt; | |
| 116 UserSection->setNumber(CurSectionNumber++); | |
| 117 UserSection->setNameStrIndex(ShStrTab->getIndex(UserSection->getName())); | |
| 118 AllSections.push_back(UserSection); | |
| 119 if (RelIt != RelE) { | |
| 120 ELFRelocationSectionBase *RelSection = *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 RelSectionList &RelSections) { | |
| 138 for (auto S : RelSections) { | |
|
Jim Stichnoth
2014/11/21 21:32:22
same comment on auto
jvoung (off chromium)
2014/11/24 21:35:46
Done.
| |
| 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 assert(!SectionNumbersAssigned); | |
| 147 SizeT CurSectionNumber = 0; | |
| 148 NullSection->setNumber(CurSectionNumber++); | |
| 149 // The rest of the fields are initialized to 0, and stay that way. | |
| 150 AllSections.push_back(NullSection); | |
| 151 | |
| 152 assignRelSectionNumInPairs<TextSectionList>(CurSectionNumber, TextSections, | |
| 153 RelTextSections, AllSections); | |
| 154 assignRelSectionNumInPairs<DataSectionList>(CurSectionNumber, DataSections, | |
| 155 RelDataSections, AllSections); | |
| 156 assignRelSectionNumInPairs<DataSectionList>(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) { | |
|
Jim Stichnoth
2014/11/21 21:32:22
The % operations could be more efficient if Align
jvoung (off chromium)
2014/11/24 21:35:46
Good point -- the align isn't statically known to
| |
| 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. | |
|
Jim Stichnoth
2014/11/21 21:32:22
Is this a TODO, or, ... ?
jvoung (off chromium)
2014/11/24 21:35:46
Done -- actually had a TODO in the .h file already
| |
| 192 void ELFObjectWriter::writeFunctionCode(const IceString &FuncName, | |
| 193 bool IsInternal, | |
| 194 const llvm::StringRef Data) { | |
| 195 assert(!SectionNumbersAssigned); | |
| 196 // TODO(jvoung): handle ffunction-sections. | |
| 197 IceString SectionName = ".text"; | |
| 198 ELFTextSection *Section = nullptr; | |
| 199 if (TextSections.size() == 0) { | |
| 200 const Elf64_Xword ShFlags = SHF_ALLOC | SHF_EXECINSTR; | |
| 201 // TODO(jvoung): Should be bundle size. Grab it from that target? | |
| 202 const Elf64_Xword ShAlign = 32; | |
| 203 Section = createSection<ELFTextSection>(SectionName, SHT_PROGBITS, ShFlags, | |
| 204 ShAlign, 0); | |
| 205 Elf64_Off OffsetInFile = alignFileOffset(Section->getSectionAlign()); | |
| 206 Section->setFileOffset(OffsetInFile); | |
| 207 TextSections.push_back(Section); | |
| 208 } else { | |
| 209 Section = TextSections[0]; | |
| 210 } | |
| 211 RelocOffsetT OffsetInSection = Section->getCurrentSize(); | |
| 212 // Function symbols are set to 0 size in the symbol table, | |
| 213 // in contrast to data symbols which have a proper size. | |
| 214 SizeT SymbolSize = 0; | |
| 215 Section->appendData(Str, Data); | |
| 216 uint8_t SymbolType; | |
| 217 uint8_t SymbolBinding; | |
| 218 if (IsInternal) { | |
| 219 SymbolType = STT_NOTYPE; | |
| 220 SymbolBinding = STB_LOCAL; | |
| 221 } else { | |
| 222 SymbolType = STT_FUNC; | |
| 223 SymbolBinding = STB_GLOBAL; | |
| 224 } | |
| 225 SymTab->createDefinedSym(FuncName, SymbolType, SymbolBinding, Section, | |
| 226 OffsetInSection, SymbolSize); | |
| 227 StrTab->add(FuncName); | |
| 228 } | |
| 229 | |
| 230 void ELFObjectWriter::writeDataInitializer(const IceString &VarName, | |
| 231 const llvm::StringRef Data) { | |
|
Jim Stichnoth
2014/11/21 21:32:22
(void)Data;
to silence unused parameter warning in
jvoung (off chromium)
2014/11/24 21:35:46
Done.
| |
| 232 assert(!SectionNumbersAssigned); | |
| 233 llvm_unreachable("TODO"); | |
| 234 StrTab->add(VarName); | |
| 235 } | |
| 236 | |
| 237 void ELFObjectWriter::writeInitialELFHeader() { | |
| 238 assert(!SectionNumbersAssigned); | |
| 239 const size_t DummySHOffset = 0; | |
| 240 const SizeT DummySHStrIndex = 0; | |
| 241 const SizeT DummyNumSections = 0; | |
| 242 if (isELF64(Ctx.getTargetArch())) { | |
| 243 writeELFHeaderInternal<true>(DummySHOffset, DummySHStrIndex, | |
| 244 DummyNumSections); | |
| 245 } else { | |
| 246 writeELFHeaderInternal<false>(DummySHOffset, DummySHStrIndex, | |
| 247 DummyNumSections); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 template <bool IsELF64> | |
| 252 void ELFObjectWriter::writeELFHeaderInternal(size_t SectionHeaderOffset, | |
| 253 SizeT SectHeaderStrIndex, | |
| 254 SizeT NumSections) { | |
| 255 // Write the e_ident: magic number, class, etc. | |
| 256 // The e_ident is byte order and ELF class independent. | |
| 257 Str.writeBytes(llvm::StringRef(ElfMagic, strlen(ElfMagic))); | |
| 258 Str.write8(IsELF64 ? ELFCLASS64 : ELFCLASS32); | |
| 259 Str.write8(ELFDATA2LSB); | |
| 260 Str.write8(EV_CURRENT); | |
| 261 Str.write8(ELFOSABI_NONE); | |
| 262 const uint8_t ELF_ABIVersion = 0; | |
| 263 Str.write8(ELF_ABIVersion); | |
| 264 Str.writeZeroPadding(EI_NIDENT - EI_PAD); | |
| 265 | |
| 266 // TODO(jvoung): Handle and test > 64K sections. See the generic ABI doc: | |
| 267 // https://refspecs.linuxbase.org/elf/gabi4+/ch4.eheader.html | |
| 268 // e_shnum should be 0 and then actual number of sections is | |
| 269 // stored in the sh_size member of the 0th section. | |
| 270 assert(NumSections < SHN_LORESERVE); | |
| 271 assert(SectHeaderStrIndex < SHN_LORESERVE); | |
| 272 | |
| 273 // Write the rest of the file header, which does depend on byte order | |
| 274 // and ELF class. | |
| 275 Str.writeLE16(ET_REL); // e_type | |
| 276 Str.writeLE16(getELFMachine(Ctx.getTargetArch())); // e_machine | |
| 277 Str.writeELFWord<IsELF64>(1); // e_version | |
| 278 // Since this is for a relocatable object, there is no entry point, | |
| 279 // and no program headers. | |
| 280 Str.writeAddrOrOffset<IsELF64>(0); // e_entry | |
| 281 Str.writeAddrOrOffset<IsELF64>(0); // e_phoff | |
| 282 Str.writeAddrOrOffset<IsELF64>(SectionHeaderOffset); // e_shoff | |
| 283 Str.writeELFWord<IsELF64>(getELFFlags(Ctx.getTargetArch())); // e_flags | |
| 284 Str.writeLE16(IsELF64 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); // e_ehsize | |
| 285 Str.writeLE16(0); // e_phentsize | |
| 286 Str.writeLE16(0); // e_phnum | |
| 287 Str.writeLE16(IsELF64 ? sizeof(Elf64_Shdr) | |
| 288 : sizeof(Elf32_Shdr)); // e_shentsize | |
| 289 Str.writeLE16(static_cast<Elf64_Half>(NumSections)); // e_shnum | |
| 290 Str.writeLE16(static_cast<Elf64_Half>(SectHeaderStrIndex)); // e_shstrndx | |
| 291 } | |
| 292 | |
| 293 void ELFObjectWriter::writeNonUserSections() { | |
| 294 bool IsELF64 = isELF64(Ctx.getTargetArch()); | |
| 295 | |
| 296 // Write out the shstrtab now that all sections are known. | |
| 297 ShStrTab->doLayout(); | |
| 298 ShStrTab->setSize(ShStrTab->getSectionDataSize()); | |
| 299 Elf64_Off ShStrTabOffset = alignFileOffset(ShStrTab->getSectionAlign()); | |
| 300 ShStrTab->setFileOffset(ShStrTabOffset); | |
| 301 Str.writeBytes(ShStrTab->getSectionData()); | |
| 302 | |
| 303 SectionList AllSections; | |
| 304 assignSectionNumbersInfo(AllSections); | |
| 305 | |
| 306 // Finalize the regular StrTab and fix up references in the SymTab. | |
| 307 StrTab->doLayout(); | |
| 308 StrTab->setSize(StrTab->getSectionDataSize()); | |
| 309 | |
| 310 SymTab->updateIndices(StrTab); | |
| 311 | |
| 312 Elf64_Off SymTabOffset = alignFileOffset(SymTab->getSectionAlign()); | |
| 313 SymTab->setFileOffset(SymTabOffset); | |
| 314 SymTab->setSize(SymTab->getSectionDataSize()); | |
| 315 SymTab->writeData(Str, IsELF64); | |
| 316 | |
| 317 Elf64_Off StrTabOffset = alignFileOffset(StrTab->getSectionAlign()); | |
| 318 StrTab->setFileOffset(StrTabOffset); | |
| 319 Str.writeBytes(StrTab->getSectionData()); | |
| 320 | |
| 321 // TODO: Write out the relocation sections. | |
| 322 // May also be able to seek around the file and resolve function calls | |
| 323 // that are for functions within the same section. | |
| 324 | |
| 325 // Write out the section headers. | |
| 326 const size_t ShdrAlign = IsELF64 ? alignof(Elf64_Shdr) : alignof(Elf32_Shdr); | |
| 327 Elf64_Off ShOffset = alignFileOffset(ShdrAlign); | |
| 328 for (const auto S : AllSections) { | |
| 329 if (IsELF64) | |
| 330 S->writeHeader<true>(Str); | |
| 331 else | |
| 332 S->writeHeader<false>(Str); | |
| 333 } | |
| 334 | |
| 335 // Finally write the updated ELF header w/ the correct number of sections. | |
| 336 Str.seek(0); | |
| 337 if (IsELF64) { | |
| 338 writeELFHeaderInternal<true>(ShOffset, ShStrTab->getNumber(), | |
| 339 AllSections.size()); | |
| 340 } else { | |
| 341 writeELFHeaderInternal<false>(ShOffset, ShStrTab->getNumber(), | |
| 342 AllSections.size()); | |
| 343 } | |
| 344 } | |
| 345 | |
| 346 } // end of namespace Ice | |
| OLD | NEW |