| 1 | //===- COFFWriter.cpp -----------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "COFFWriter.h" |
| 10 | #include "COFFObject.h" |
| 11 | #include "llvm/ADT/ArrayRef.h" |
| 12 | #include "llvm/ADT/StringRef.h" |
| 13 | #include "llvm/BinaryFormat/COFF.h" |
| 14 | #include "llvm/Object/COFF.h" |
| 15 | #include "llvm/Support/CRC.h" |
| 16 | #include "llvm/Support/Endian.h" |
| 17 | #include "llvm/Support/Errc.h" |
| 18 | #include "llvm/Support/ErrorHandling.h" |
| 19 | #include <cstddef> |
| 20 | #include <cstdint> |
| 21 | |
| 22 | namespace llvm { |
| 23 | namespace objcopy { |
| 24 | namespace coff { |
| 25 | |
| 26 | using namespace object; |
| 27 | using namespace COFF; |
| 28 | |
| 29 | Error COFFWriter::finalizeRelocTargets() { |
| 30 | for (Section &Sec : Obj.getMutableSections()) { |
| 31 | for (Relocation &R : Sec.Relocs) { |
| 32 | const Symbol *Sym = Obj.findSymbol(UniqueId: R.Target); |
| 33 | if (Sym == nullptr) |
| 34 | return createStringError(EC: object_error::invalid_symbol_index, |
| 35 | Fmt: "relocation target '%s' (%zu) not found" , |
| 36 | Vals: R.TargetName.str().c_str(), Vals: R.Target); |
| 37 | R.Reloc.SymbolTableIndex = Sym->RawIndex; |
| 38 | } |
| 39 | } |
| 40 | return Error::success(); |
| 41 | } |
| 42 | |
| 43 | Error COFFWriter::finalizeSymbolContents() { |
| 44 | for (Symbol &Sym : Obj.getMutableSymbols()) { |
| 45 | if (Sym.TargetSectionId <= 0) { |
| 46 | // Undefined, or a special kind of symbol. These negative values |
| 47 | // are stored in the SectionNumber field which is unsigned. |
| 48 | Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId); |
| 49 | } else { |
| 50 | const Section *Sec = Obj.findSection(UniqueId: Sym.TargetSectionId); |
| 51 | if (Sec == nullptr) |
| 52 | return createStringError(EC: object_error::invalid_symbol_index, |
| 53 | Fmt: "symbol '%s' points to a removed section" , |
| 54 | Vals: Sym.Name.str().c_str()); |
| 55 | Sym.Sym.SectionNumber = Sec->Index; |
| 56 | |
| 57 | if (Sym.Sym.NumberOfAuxSymbols == 1 && |
| 58 | Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) { |
| 59 | coff_aux_section_definition *SD = |
| 60 | reinterpret_cast<coff_aux_section_definition *>( |
| 61 | Sym.AuxData[0].Opaque); |
| 62 | uint32_t SDSectionNumber; |
| 63 | if (Sym.AssociativeComdatTargetSectionId == 0) { |
| 64 | // Not a comdat associative section; just set the Number field to |
| 65 | // the number of the section itself. |
| 66 | SDSectionNumber = Sec->Index; |
| 67 | } else { |
| 68 | Sec = Obj.findSection(UniqueId: Sym.AssociativeComdatTargetSectionId); |
| 69 | if (Sec == nullptr) |
| 70 | return createStringError( |
| 71 | EC: object_error::invalid_symbol_index, |
| 72 | Fmt: "symbol '%s' is associative to a removed section" , |
| 73 | Vals: Sym.Name.str().c_str()); |
| 74 | SDSectionNumber = Sec->Index; |
| 75 | } |
| 76 | // Update the section definition with the new section number. |
| 77 | SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber); |
| 78 | SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16); |
| 79 | } |
| 80 | } |
| 81 | // Check that we actually have got AuxData to match the weak symbol target |
| 82 | // we want to set. Only >= 1 would be required, but only == 1 makes sense. |
| 83 | if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) { |
| 84 | coff_aux_weak_external *WE = |
| 85 | reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque); |
| 86 | const Symbol *Target = Obj.findSymbol(UniqueId: *Sym.WeakTargetSymbolId); |
| 87 | if (Target == nullptr) |
| 88 | return createStringError(EC: object_error::invalid_symbol_index, |
| 89 | Fmt: "symbol '%s' is missing its weak target" , |
| 90 | Vals: Sym.Name.str().c_str()); |
| 91 | WE->TagIndex = Target->RawIndex; |
| 92 | } |
| 93 | } |
| 94 | return Error::success(); |
| 95 | } |
| 96 | |
| 97 | Error COFFWriter::finalizeSymIdxContents() { |
| 98 | // CFGuards shouldn't be present in PE. |
| 99 | if (Obj.IsPE) |
| 100 | return Error::success(); |
| 101 | |
| 102 | // Currently handle only sections consisting only of .symidx. |
| 103 | // TODO: other sections such as .impcall and .hybmp$x require more complex |
| 104 | // handling as they have more complex layout. |
| 105 | auto IsSymIdxSection = [](StringRef Name) { |
| 106 | return Name == ".gljmp$y" || Name == ".giats$y" || Name == ".gfids$y" || |
| 107 | Name == ".gehcont$y" ; |
| 108 | }; |
| 109 | |
| 110 | DenseMap<size_t, size_t> SymIdMap; |
| 111 | SmallDenseMap<ssize_t, coff_aux_section_definition *, 4> SecIdMap; |
| 112 | for (Symbol &Sym : Obj.getMutableSymbols()) { |
| 113 | SymIdMap[Sym.OriginalRawIndex] = Sym.RawIndex; |
| 114 | |
| 115 | // We collect only definition symbols of the sections to update the |
| 116 | // checksums. |
| 117 | if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC && |
| 118 | Sym.Sym.NumberOfAuxSymbols == 1 && Sym.Sym.Value == 0 && |
| 119 | IsSymIdxSection(Sym.Name)) |
| 120 | SecIdMap[Sym.TargetSectionId] = |
| 121 | reinterpret_cast<coff_aux_section_definition *>( |
| 122 | Sym.AuxData[0].Opaque); |
| 123 | } |
| 124 | |
| 125 | for (Section &Sec : Obj.getMutableSections()) { |
| 126 | if (!IsSymIdxSection(Sec.Name)) |
| 127 | continue; |
| 128 | |
| 129 | ArrayRef<uint8_t> RawIds = Sec.getContents(); |
| 130 | // Nothing to do and also the checksum will be -1 instead of 0 if we |
| 131 | // recalculate it on empty input. |
| 132 | if (RawIds.size() == 0) |
| 133 | continue; |
| 134 | |
| 135 | auto SecDefIt = SecIdMap.find(Val: Sec.UniqueId); |
| 136 | if (SecDefIt == SecIdMap.end()) |
| 137 | return createStringError(EC: object_error::invalid_symbol_index, |
| 138 | Fmt: "section '%s' does not have the corresponding " |
| 139 | "symbol or the symbol has unexpected format" , |
| 140 | Vals: Sec.Name.str().c_str()); |
| 141 | |
| 142 | // Create updated content. |
| 143 | ArrayRef<support::ulittle32_t> Ids( |
| 144 | reinterpret_cast<const support::ulittle32_t *>(RawIds.data()), |
| 145 | RawIds.size() / 4); |
| 146 | std::vector<support::ulittle32_t> NewIds; |
| 147 | for (support::ulittle32_t Id : Ids) { |
| 148 | auto SymIdIt = SymIdMap.find(Val: Id); |
| 149 | if (SymIdIt == SymIdMap.end()) |
| 150 | return createStringError(EC: object_error::invalid_symbol_index, |
| 151 | Fmt: "section '%s' contains a .symidx (%d) that is " |
| 152 | "incorrect or was stripped" , |
| 153 | Vals: Sec.Name.str().c_str(), Vals: Id.value()); |
| 154 | NewIds.push_back(x: support::ulittle32_t(SymIdIt->getSecond())); |
| 155 | } |
| 156 | ArrayRef<uint8_t> NewRawIds(reinterpret_cast<uint8_t *>(NewIds.data()), |
| 157 | RawIds.size()); |
| 158 | // Update the checksum. |
| 159 | JamCRC JC(/*Init=*/0); |
| 160 | JC.update(Data: NewRawIds); |
| 161 | SecDefIt->getSecond()->CheckSum = JC.getCRC(); |
| 162 | // Set new content. |
| 163 | Sec.setOwnedContents(NewRawIds.vec()); |
| 164 | } |
| 165 | return Error::success(); |
| 166 | } |
| 167 | |
| 168 | void COFFWriter::layoutSections() { |
| 169 | for (auto &S : Obj.getMutableSections()) { |
| 170 | if (S.Header.SizeOfRawData > 0) |
| 171 | S.Header.PointerToRawData = FileSize; |
| 172 | else |
| 173 | S.Header.PointerToRawData = 0; |
| 174 | FileSize += S.Header.SizeOfRawData; // For executables, this is already |
| 175 | // aligned to FileAlignment. |
| 176 | if (S.Relocs.size() >= 0xffff) { |
| 177 | S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; |
| 178 | S.Header.NumberOfRelocations = 0xffff; |
| 179 | S.Header.PointerToRelocations = FileSize; |
| 180 | FileSize += sizeof(coff_relocation); |
| 181 | } else { |
| 182 | S.Header.NumberOfRelocations = S.Relocs.size(); |
| 183 | S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0; |
| 184 | } |
| 185 | |
| 186 | FileSize += S.Relocs.size() * sizeof(coff_relocation); |
| 187 | FileSize = alignTo(Value: FileSize, Align: FileAlignment); |
| 188 | |
| 189 | if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) |
| 190 | SizeOfInitializedData += S.Header.SizeOfRawData; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | Expected<size_t> COFFWriter::finalizeStringTable() { |
| 195 | for (const auto &S : Obj.getSections()) |
| 196 | if (S.Name.size() > COFF::NameSize) { |
| 197 | // Put the section name at the start of strtab to ensure its offset is |
| 198 | // less than Max7DecimalOffset. Otherwise, lldb/gdb will not read it. |
| 199 | StrTabBuilder.add(S: S.Name, /*Priority=*/UINT8_MAX); |
| 200 | } |
| 201 | |
| 202 | for (const auto &S : Obj.getSymbols()) |
| 203 | if (S.Name.size() > COFF::NameSize) |
| 204 | StrTabBuilder.add(S: S.Name); |
| 205 | |
| 206 | StrTabBuilder.finalize(); |
| 207 | |
| 208 | for (auto &S : Obj.getMutableSections()) { |
| 209 | memset(s: S.Header.Name, c: 0, n: sizeof(S.Header.Name)); |
| 210 | if (S.Name.size() <= COFF::NameSize) { |
| 211 | // Short names can go in the field directly. |
| 212 | memcpy(dest: S.Header.Name, src: S.Name.data(), n: S.Name.size()); |
| 213 | } else { |
| 214 | // Offset of the section name in the string table. |
| 215 | size_t Offset = StrTabBuilder.getOffset(S: S.Name); |
| 216 | if (!COFF::encodeSectionName(Out: S.Header.Name, Offset)) |
| 217 | return createStringError(EC: object_error::invalid_section_index, |
| 218 | S: "COFF string table is greater than 64GB, " |
| 219 | "unable to encode section name offset" ); |
| 220 | } |
| 221 | } |
| 222 | for (auto &S : Obj.getMutableSymbols()) { |
| 223 | if (S.Name.size() > COFF::NameSize) { |
| 224 | S.Sym.Name.Offset.Zeroes = 0; |
| 225 | S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S: S.Name); |
| 226 | } else { |
| 227 | strncpy(dest: S.Sym.Name.ShortName, src: S.Name.data(), n: COFF::NameSize); |
| 228 | } |
| 229 | } |
| 230 | return StrTabBuilder.getSize(); |
| 231 | } |
| 232 | |
| 233 | template <class SymbolTy> |
| 234 | std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() { |
| 235 | size_t RawSymIndex = 0; |
| 236 | for (auto &S : Obj.getMutableSymbols()) { |
| 237 | // Symbols normally have NumberOfAuxSymbols set correctly all the time. |
| 238 | // For file symbols, we need to know the output file's symbol size to be |
| 239 | // able to calculate the number of slots it occupies. |
| 240 | if (!S.AuxFile.empty()) |
| 241 | S.Sym.NumberOfAuxSymbols = |
| 242 | alignTo(Value: S.AuxFile.size(), Align: sizeof(SymbolTy)) / sizeof(SymbolTy); |
| 243 | S.RawIndex = RawSymIndex; |
| 244 | RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols; |
| 245 | } |
| 246 | return std::make_pair(x: RawSymIndex * sizeof(SymbolTy), y: sizeof(SymbolTy)); |
| 247 | } |
| 248 | |
| 249 | Error COFFWriter::finalize(bool IsBigObj) { |
| 250 | size_t SymTabSize, SymbolSize; |
| 251 | std::tie(args&: SymTabSize, args&: SymbolSize) = IsBigObj |
| 252 | ? finalizeSymbolTable<coff_symbol32>() |
| 253 | : finalizeSymbolTable<coff_symbol16>(); |
| 254 | |
| 255 | if (Error E = finalizeRelocTargets()) |
| 256 | return E; |
| 257 | if (Error E = finalizeSymbolContents()) |
| 258 | return E; |
| 259 | if (Error E = finalizeSymIdxContents()) |
| 260 | return E; |
| 261 | |
| 262 | size_t = 0; |
| 263 | FileAlignment = 1; |
| 264 | size_t = 0; |
| 265 | if (Obj.IsPE) { |
| 266 | Obj.DosHeader.AddressOfNewExeHeader = |
| 267 | sizeof(Obj.DosHeader) + Obj.DosStub.size(); |
| 268 | SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic); |
| 269 | |
| 270 | FileAlignment = Obj.PeHeader.FileAlignment; |
| 271 | Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size(); |
| 272 | |
| 273 | PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header); |
| 274 | SizeOfHeaders += |
| 275 | PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); |
| 276 | } |
| 277 | Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size(); |
| 278 | SizeOfHeaders += |
| 279 | IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header); |
| 280 | SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size(); |
| 281 | SizeOfHeaders = alignTo(Value: SizeOfHeaders, Align: FileAlignment); |
| 282 | |
| 283 | Obj.CoffFileHeader.SizeOfOptionalHeader = |
| 284 | PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); |
| 285 | |
| 286 | FileSize = SizeOfHeaders; |
| 287 | SizeOfInitializedData = 0; |
| 288 | |
| 289 | layoutSections(); |
| 290 | |
| 291 | if (Obj.IsPE) { |
| 292 | Obj.PeHeader.SizeOfHeaders = SizeOfHeaders; |
| 293 | Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData; |
| 294 | |
| 295 | if (!Obj.getSections().empty()) { |
| 296 | const Section &S = Obj.getSections().back(); |
| 297 | Obj.PeHeader.SizeOfImage = |
| 298 | alignTo(Value: S.Header.VirtualAddress + S.Header.VirtualSize, |
| 299 | Align: Obj.PeHeader.SectionAlignment); |
| 300 | } |
| 301 | |
| 302 | // If the PE header had a checksum, clear it, since it isn't valid |
| 303 | // any longer. (We don't calculate a new one.) |
| 304 | Obj.PeHeader.CheckSum = 0; |
| 305 | } |
| 306 | |
| 307 | Expected<size_t> StrTabSizeOrErr = finalizeStringTable(); |
| 308 | if (!StrTabSizeOrErr) |
| 309 | return StrTabSizeOrErr.takeError(); |
| 310 | |
| 311 | size_t StrTabSize = *StrTabSizeOrErr; |
| 312 | |
| 313 | size_t PointerToSymbolTable = FileSize; |
| 314 | // StrTabSize <= 4 is the size of an empty string table, only consisting |
| 315 | // of the length field. |
| 316 | if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) { |
| 317 | // For executables, don't point to the symbol table and skip writing |
| 318 | // the length field, if both the symbol and string tables are empty. |
| 319 | PointerToSymbolTable = 0; |
| 320 | StrTabSize = 0; |
| 321 | } |
| 322 | |
| 323 | size_t NumRawSymbols = SymTabSize / SymbolSize; |
| 324 | Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable; |
| 325 | Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; |
| 326 | FileSize += SymTabSize + StrTabSize; |
| 327 | FileSize = alignTo(Value: FileSize, Align: FileAlignment); |
| 328 | |
| 329 | return Error::success(); |
| 330 | } |
| 331 | |
| 332 | void COFFWriter::(bool IsBigObj) { |
| 333 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); |
| 334 | if (Obj.IsPE) { |
| 335 | memcpy(dest: Ptr, src: &Obj.DosHeader, n: sizeof(Obj.DosHeader)); |
| 336 | Ptr += sizeof(Obj.DosHeader); |
| 337 | memcpy(dest: Ptr, src: Obj.DosStub.data(), n: Obj.DosStub.size()); |
| 338 | Ptr += Obj.DosStub.size(); |
| 339 | memcpy(dest: Ptr, src: PEMagic, n: sizeof(PEMagic)); |
| 340 | Ptr += sizeof(PEMagic); |
| 341 | } |
| 342 | if (!IsBigObj) { |
| 343 | memcpy(dest: Ptr, src: &Obj.CoffFileHeader, n: sizeof(Obj.CoffFileHeader)); |
| 344 | Ptr += sizeof(Obj.CoffFileHeader); |
| 345 | } else { |
| 346 | // Generate a coff_bigobj_file_header, filling it in with the values |
| 347 | // from Obj.CoffFileHeader. All extra fields that don't exist in |
| 348 | // coff_file_header can be set to hardcoded values. |
| 349 | coff_bigobj_file_header ; |
| 350 | BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN; |
| 351 | BigObjHeader.Sig2 = 0xffff; |
| 352 | BigObjHeader.Version = BigObjHeader::MinBigObjectVersion; |
| 353 | BigObjHeader.Machine = Obj.CoffFileHeader.Machine; |
| 354 | BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp; |
| 355 | memcpy(dest: BigObjHeader.UUID, src: BigObjMagic, n: sizeof(BigObjMagic)); |
| 356 | BigObjHeader.unused1 = 0; |
| 357 | BigObjHeader.unused2 = 0; |
| 358 | BigObjHeader.unused3 = 0; |
| 359 | BigObjHeader.unused4 = 0; |
| 360 | // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus |
| 361 | // get the original one instead. |
| 362 | BigObjHeader.NumberOfSections = Obj.getSections().size(); |
| 363 | BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable; |
| 364 | BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols; |
| 365 | |
| 366 | memcpy(dest: Ptr, src: &BigObjHeader, n: sizeof(BigObjHeader)); |
| 367 | Ptr += sizeof(BigObjHeader); |
| 368 | } |
| 369 | if (Obj.IsPE) { |
| 370 | if (Obj.Is64) { |
| 371 | memcpy(dest: Ptr, src: &Obj.PeHeader, n: sizeof(Obj.PeHeader)); |
| 372 | Ptr += sizeof(Obj.PeHeader); |
| 373 | } else { |
| 374 | pe32_header ; |
| 375 | copyPeHeader(Dest&: PeHeader, Src: Obj.PeHeader); |
| 376 | // The pe32plus_header (stored in Object) lacks the BaseOfData field. |
| 377 | PeHeader.BaseOfData = Obj.BaseOfData; |
| 378 | |
| 379 | memcpy(dest: Ptr, src: &PeHeader, n: sizeof(PeHeader)); |
| 380 | Ptr += sizeof(PeHeader); |
| 381 | } |
| 382 | for (const auto &DD : Obj.DataDirectories) { |
| 383 | memcpy(dest: Ptr, src: &DD, n: sizeof(DD)); |
| 384 | Ptr += sizeof(DD); |
| 385 | } |
| 386 | } |
| 387 | for (const auto &S : Obj.getSections()) { |
| 388 | memcpy(dest: Ptr, src: &S.Header, n: sizeof(S.Header)); |
| 389 | Ptr += sizeof(S.Header); |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | void COFFWriter::writeSections() { |
| 394 | for (const auto &S : Obj.getSections()) { |
| 395 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
| 396 | S.Header.PointerToRawData; |
| 397 | ArrayRef<uint8_t> Contents = S.getContents(); |
| 398 | llvm::copy(Range&: Contents, Out: Ptr); |
| 399 | |
| 400 | // For executable sections, pad the remainder of the raw data size with |
| 401 | // 0xcc, which is int3 on x86. |
| 402 | if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) && |
| 403 | S.Header.SizeOfRawData > Contents.size()) |
| 404 | memset(s: Ptr + Contents.size(), c: 0xcc, |
| 405 | n: S.Header.SizeOfRawData - Contents.size()); |
| 406 | |
| 407 | Ptr += S.Header.SizeOfRawData; |
| 408 | |
| 409 | if (S.Relocs.size() >= 0xffff) { |
| 410 | object::coff_relocation R; |
| 411 | R.VirtualAddress = S.Relocs.size() + 1; |
| 412 | R.SymbolTableIndex = 0; |
| 413 | R.Type = 0; |
| 414 | memcpy(dest: Ptr, src: &R, n: sizeof(R)); |
| 415 | Ptr += sizeof(R); |
| 416 | } |
| 417 | for (const auto &R : S.Relocs) { |
| 418 | memcpy(dest: Ptr, src: &R.Reloc, n: sizeof(R.Reloc)); |
| 419 | Ptr += sizeof(R.Reloc); |
| 420 | } |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | template <class SymbolTy> void COFFWriter::writeSymbolStringTables() { |
| 425 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
| 426 | Obj.CoffFileHeader.PointerToSymbolTable; |
| 427 | for (const auto &S : Obj.getSymbols()) { |
| 428 | // Convert symbols back to the right size, from coff_symbol32. |
| 429 | copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr), |
| 430 | S.Sym); |
| 431 | Ptr += sizeof(SymbolTy); |
| 432 | if (!S.AuxFile.empty()) { |
| 433 | // For file symbols, just write the string into the aux symbol slots, |
| 434 | // assuming that the unwritten parts are initialized to zero in the memory |
| 435 | // mapped file. |
| 436 | llvm::copy(Range: S.AuxFile, Out: Ptr); |
| 437 | Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy); |
| 438 | } else { |
| 439 | // For other auxillary symbols, write their opaque payload into one symbol |
| 440 | // table slot each. For big object files, the symbols are larger than the |
| 441 | // opaque auxillary symbol struct and we leave padding at the end of each |
| 442 | // entry. |
| 443 | for (const AuxSymbol &AuxSym : S.AuxData) { |
| 444 | ArrayRef<uint8_t> Ref = AuxSym.getRef(); |
| 445 | llvm::copy(Range&: Ref, Out: Ptr); |
| 446 | Ptr += sizeof(SymbolTy); |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) { |
| 451 | // Always write a string table in object files, even an empty one. |
| 452 | StrTabBuilder.write(Buf: Ptr); |
| 453 | Ptr += StrTabBuilder.getSize(); |
| 454 | } |
| 455 | } |
| 456 | |
| 457 | Error COFFWriter::write(bool IsBigObj) { |
| 458 | if (Error E = finalize(IsBigObj)) |
| 459 | return E; |
| 460 | |
| 461 | Buf = WritableMemoryBuffer::getNewMemBuffer(Size: FileSize); |
| 462 | if (!Buf) |
| 463 | return createStringError(EC: llvm::errc::not_enough_memory, |
| 464 | S: "failed to allocate memory buffer of " + |
| 465 | Twine::utohexstr(Val: FileSize) + " bytes." ); |
| 466 | |
| 467 | writeHeaders(IsBigObj); |
| 468 | writeSections(); |
| 469 | if (IsBigObj) |
| 470 | writeSymbolStringTables<coff_symbol32>(); |
| 471 | else |
| 472 | writeSymbolStringTables<coff_symbol16>(); |
| 473 | |
| 474 | if (Obj.IsPE) |
| 475 | if (Error E = patchDebugDirectory()) |
| 476 | return E; |
| 477 | |
| 478 | // TODO: Implement direct writing to the output stream (without intermediate |
| 479 | // memory buffer Buf). |
| 480 | Out.write(Ptr: Buf->getBufferStart(), Size: Buf->getBufferSize()); |
| 481 | return Error::success(); |
| 482 | } |
| 483 | |
| 484 | Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) { |
| 485 | for (const auto &S : Obj.getSections()) { |
| 486 | if (RVA >= S.Header.VirtualAddress && |
| 487 | RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData) |
| 488 | return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress; |
| 489 | } |
| 490 | return createStringError(EC: object_error::parse_failed, |
| 491 | S: "debug directory payload not found" ); |
| 492 | } |
| 493 | |
| 494 | // Locate which sections contain the debug directories, iterate over all |
| 495 | // the debug_directory structs in there, and set the PointerToRawData field |
| 496 | // in all of them, according to their new physical location in the file. |
| 497 | Error COFFWriter::patchDebugDirectory() { |
| 498 | if (Obj.DataDirectories.size() <= DEBUG_DIRECTORY) |
| 499 | return Error::success(); |
| 500 | const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY]; |
| 501 | if (Dir->Size <= 0) |
| 502 | return Error::success(); |
| 503 | for (const auto &S : Obj.getSections()) { |
| 504 | if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress && |
| 505 | Dir->RelativeVirtualAddress < |
| 506 | S.Header.VirtualAddress + S.Header.SizeOfRawData) { |
| 507 | if (Dir->RelativeVirtualAddress + Dir->Size > |
| 508 | S.Header.VirtualAddress + S.Header.SizeOfRawData) |
| 509 | return createStringError(EC: object_error::parse_failed, |
| 510 | S: "debug directory extends past end of section" ); |
| 511 | |
| 512 | size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress; |
| 513 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
| 514 | S.Header.PointerToRawData + Offset; |
| 515 | uint8_t *End = Ptr + Dir->Size; |
| 516 | while (Ptr < End) { |
| 517 | debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr); |
| 518 | if (Debug->PointerToRawData) { |
| 519 | if (Expected<uint32_t> FilePosOrErr = |
| 520 | virtualAddressToFileAddress(RVA: Debug->AddressOfRawData)) |
| 521 | Debug->PointerToRawData = *FilePosOrErr; |
| 522 | else |
| 523 | return FilePosOrErr.takeError(); |
| 524 | } |
| 525 | Ptr += sizeof(debug_directory); |
| 526 | Offset += sizeof(debug_directory); |
| 527 | } |
| 528 | // Debug directory found and patched, all done. |
| 529 | return Error::success(); |
| 530 | } |
| 531 | } |
| 532 | return createStringError(EC: object_error::parse_failed, |
| 533 | S: "debug directory not found" ); |
| 534 | } |
| 535 | |
| 536 | Error COFFWriter::write() { |
| 537 | bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16; |
| 538 | if (IsBigObj && Obj.IsPE) |
| 539 | return createStringError(EC: object_error::parse_failed, |
| 540 | S: "too many sections for executable" ); |
| 541 | return write(IsBigObj); |
| 542 | } |
| 543 | |
| 544 | } // end namespace coff |
| 545 | } // end namespace objcopy |
| 546 | } // end namespace llvm |
| 547 | |