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