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