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