1 //===- Writer.cpp ---------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "Writer.h" 11 #include "Object.h" 12 #include "llvm-objcopy.h" 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/BinaryFormat/COFF.h" 16 #include "llvm/Object/COFF.h" 17 #include "llvm/Support/ErrorHandling.h" 18 #include <cstddef> 19 #include <cstdint> 20 21 namespace llvm { 22 namespace objcopy { 23 namespace coff { 24 25 using namespace object; 26 using namespace COFF; 27 28 Error COFFWriter::finalizeRelocTargets() { 29 for (Section &Sec : Obj.Sections) { 30 for (Relocation &R : Sec.Relocs) { 31 const Symbol *Sym = Obj.findSymbol(R.Target); 32 if (Sym == nullptr) 33 return make_error<StringError>("Relocation target " + R.TargetName + 34 " (" + Twine(R.Target) + 35 ") not found", 36 object_error::invalid_symbol_index); 37 R.Reloc.SymbolTableIndex = Sym->RawIndex; 38 } 39 } 40 return Error::success(); 41 } 42 43 void COFFWriter::layoutSections() { 44 for (auto &S : Obj.Sections) { 45 if (S.Header.SizeOfRawData > 0) 46 S.Header.PointerToRawData = FileSize; 47 FileSize += S.Header.SizeOfRawData; // For executables, this is already 48 // aligned to FileAlignment. 49 S.Header.NumberOfRelocations = S.Relocs.size(); 50 S.Header.PointerToRelocations = 51 S.Header.NumberOfRelocations > 0 ? FileSize : 0; 52 FileSize += S.Relocs.size() * sizeof(coff_relocation); 53 FileSize = alignTo(FileSize, FileAlignment); 54 55 if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) 56 SizeOfInitializedData += S.Header.SizeOfRawData; 57 } 58 } 59 60 size_t COFFWriter::finalizeStringTable() { 61 for (auto &S : Obj.Sections) 62 if (S.Name.size() > COFF::NameSize) 63 StrTabBuilder.add(S.Name); 64 65 for (const auto &S : Obj.getSymbols()) 66 if (S.Name.size() > COFF::NameSize) 67 StrTabBuilder.add(S.Name); 68 69 StrTabBuilder.finalize(); 70 71 for (auto &S : Obj.Sections) { 72 if (S.Name.size() > COFF::NameSize) { 73 snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d", 74 (int)StrTabBuilder.getOffset(S.Name)); 75 } else { 76 strncpy(S.Header.Name, S.Name.data(), COFF::NameSize); 77 } 78 } 79 for (auto &S : Obj.getMutableSymbols()) { 80 if (S.Name.size() > COFF::NameSize) { 81 S.Sym.Name.Offset.Zeroes = 0; 82 S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name); 83 } else { 84 strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize); 85 } 86 } 87 return StrTabBuilder.getSize(); 88 } 89 90 template <class SymbolTy> 91 std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() { 92 size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy); 93 for (const auto &S : Obj.getSymbols()) 94 SymTabSize += S.AuxData.size(); 95 return std::make_pair(SymTabSize, sizeof(SymbolTy)); 96 } 97 98 Error COFFWriter::finalize(bool IsBigObj) { 99 if (Error E = finalizeRelocTargets()) 100 return E; 101 102 size_t SizeOfHeaders = 0; 103 FileAlignment = 1; 104 size_t PeHeaderSize = 0; 105 if (Obj.IsPE) { 106 Obj.DosHeader.AddressOfNewExeHeader = 107 sizeof(Obj.DosHeader) + Obj.DosStub.size(); 108 SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic); 109 110 FileAlignment = Obj.PeHeader.FileAlignment; 111 Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size(); 112 113 PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header); 114 SizeOfHeaders += 115 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); 116 } 117 Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size(); 118 SizeOfHeaders += 119 IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header); 120 SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size(); 121 SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment); 122 123 Obj.CoffFileHeader.SizeOfOptionalHeader = 124 PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); 125 126 FileSize = SizeOfHeaders; 127 SizeOfInitializedData = 0; 128 129 layoutSections(); 130 131 if (Obj.IsPE) { 132 Obj.PeHeader.SizeOfHeaders = SizeOfHeaders; 133 Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData; 134 135 if (!Obj.Sections.empty()) { 136 const Section &S = Obj.Sections.back(); 137 Obj.PeHeader.SizeOfImage = 138 alignTo(S.Header.VirtualAddress + S.Header.VirtualSize, 139 Obj.PeHeader.SectionAlignment); 140 } 141 142 // If the PE header had a checksum, clear it, since it isn't valid 143 // any longer. (We don't calculate a new one.) 144 Obj.PeHeader.CheckSum = 0; 145 } 146 147 size_t StrTabSize = finalizeStringTable(); 148 size_t SymTabSize, SymbolSize; 149 std::tie(SymTabSize, SymbolSize) = IsBigObj 150 ? finalizeSymbolTable<coff_symbol32>() 151 : finalizeSymbolTable<coff_symbol16>(); 152 153 size_t PointerToSymbolTable = FileSize; 154 // StrTabSize <= 4 is the size of an empty string table, only consisting 155 // of the length field. 156 if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) { 157 // For executables, don't point to the symbol table and skip writing 158 // the length field, if both the symbol and string tables are empty. 159 PointerToSymbolTable = 0; 160 StrTabSize = 0; 161 } 162 163 size_t NumRawSymbols = SymTabSize / SymbolSize; 164 Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable; 165 Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; 166 FileSize += SymTabSize + StrTabSize; 167 FileSize = alignTo(FileSize, FileAlignment); 168 169 return Error::success(); 170 } 171 172 void COFFWriter::writeHeaders(bool IsBigObj) { 173 uint8_t *Ptr = Buf.getBufferStart(); 174 if (Obj.IsPE) { 175 memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader)); 176 Ptr += sizeof(Obj.DosHeader); 177 memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size()); 178 Ptr += Obj.DosStub.size(); 179 memcpy(Ptr, PEMagic, sizeof(PEMagic)); 180 Ptr += sizeof(PEMagic); 181 } 182 if (!IsBigObj) { 183 memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader)); 184 Ptr += sizeof(Obj.CoffFileHeader); 185 } else { 186 // Generate a coff_bigobj_file_header, filling it in with the values 187 // from Obj.CoffFileHeader. All extra fields that don't exist in 188 // coff_file_header can be set to hardcoded values. 189 coff_bigobj_file_header BigObjHeader; 190 BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN; 191 BigObjHeader.Sig2 = 0xffff; 192 BigObjHeader.Version = BigObjHeader::MinBigObjectVersion; 193 BigObjHeader.Machine = Obj.CoffFileHeader.Machine; 194 BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp; 195 memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic)); 196 BigObjHeader.unused1 = 0; 197 BigObjHeader.unused2 = 0; 198 BigObjHeader.unused3 = 0; 199 BigObjHeader.unused4 = 0; 200 // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus 201 // get the original one instead. 202 BigObjHeader.NumberOfSections = Obj.Sections.size(); 203 BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable; 204 BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols; 205 206 memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader)); 207 Ptr += sizeof(BigObjHeader); 208 } 209 if (Obj.IsPE) { 210 if (Obj.Is64) { 211 memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader)); 212 Ptr += sizeof(Obj.PeHeader); 213 } else { 214 pe32_header PeHeader; 215 copyPeHeader(PeHeader, Obj.PeHeader); 216 // The pe32plus_header (stored in Object) lacks the BaseOfData field. 217 PeHeader.BaseOfData = Obj.BaseOfData; 218 219 memcpy(Ptr, &PeHeader, sizeof(PeHeader)); 220 Ptr += sizeof(PeHeader); 221 } 222 for (const auto &DD : Obj.DataDirectories) { 223 memcpy(Ptr, &DD, sizeof(DD)); 224 Ptr += sizeof(DD); 225 } 226 } 227 for (const auto &S : Obj.Sections) { 228 memcpy(Ptr, &S.Header, sizeof(S.Header)); 229 Ptr += sizeof(S.Header); 230 } 231 } 232 233 void COFFWriter::writeSections() { 234 for (const auto &S : Obj.Sections) { 235 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData; 236 std::copy(S.Contents.begin(), S.Contents.end(), Ptr); 237 238 // For executable sections, pad the remainder of the raw data size with 239 // 0xcc, which is int3 on x86. 240 if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) && 241 S.Header.SizeOfRawData > S.Contents.size()) 242 memset(Ptr + S.Contents.size(), 0xcc, 243 S.Header.SizeOfRawData - S.Contents.size()); 244 245 Ptr += S.Header.SizeOfRawData; 246 for (const auto &R : S.Relocs) { 247 memcpy(Ptr, &R.Reloc, sizeof(R.Reloc)); 248 Ptr += sizeof(R.Reloc); 249 } 250 } 251 } 252 253 template <class SymbolTy> void COFFWriter::writeSymbolStringTables() { 254 uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable; 255 for (const auto &S : Obj.getSymbols()) { 256 // Convert symbols back to the right size, from coff_symbol32. 257 copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr), 258 S.Sym); 259 Ptr += sizeof(SymbolTy); 260 std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr); 261 Ptr += S.AuxData.size(); 262 } 263 if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) { 264 // Always write a string table in object files, even an empty one. 265 StrTabBuilder.write(Ptr); 266 Ptr += StrTabBuilder.getSize(); 267 } 268 } 269 270 Error COFFWriter::write(bool IsBigObj) { 271 if (Error E = finalize(IsBigObj)) 272 return E; 273 274 Buf.allocate(FileSize); 275 276 writeHeaders(IsBigObj); 277 writeSections(); 278 if (IsBigObj) 279 writeSymbolStringTables<coff_symbol32>(); 280 else 281 writeSymbolStringTables<coff_symbol16>(); 282 283 if (Obj.IsPE) 284 if (Error E = patchDebugDirectory()) 285 return E; 286 287 return Buf.commit(); 288 } 289 290 // Locate which sections contain the debug directories, iterate over all 291 // the debug_directory structs in there, and set the PointerToRawData field 292 // in all of them, according to their new physical location in the file. 293 Error COFFWriter::patchDebugDirectory() { 294 if (Obj.DataDirectories.size() < DEBUG_DIRECTORY) 295 return Error::success(); 296 const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY]; 297 if (Dir->Size <= 0) 298 return Error::success(); 299 for (const auto &S : Obj.Sections) { 300 if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress && 301 Dir->RelativeVirtualAddress < 302 S.Header.VirtualAddress + S.Header.SizeOfRawData) { 303 if (Dir->RelativeVirtualAddress + Dir->Size > 304 S.Header.VirtualAddress + S.Header.SizeOfRawData) 305 return make_error<StringError>( 306 "Debug directory extends past end of section", 307 object_error::parse_failed); 308 309 size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress; 310 uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset; 311 uint8_t *End = Ptr + Dir->Size; 312 while (Ptr < End) { 313 debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr); 314 Debug->PointerToRawData = 315 S.Header.PointerToRawData + Offset + sizeof(debug_directory); 316 Ptr += sizeof(debug_directory) + Debug->SizeOfData; 317 Offset += sizeof(debug_directory) + Debug->SizeOfData; 318 } 319 // Debug directory found and patched, all done. 320 return Error::success(); 321 } 322 } 323 return make_error<StringError>("Debug directory not found", 324 object_error::parse_failed); 325 } 326 327 Error COFFWriter::write() { 328 bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16; 329 if (IsBigObj && Obj.IsPE) 330 return make_error<StringError>("Too many sections for executable", 331 object_error::parse_failed); 332 return write(IsBigObj); 333 } 334 335 } // end namespace coff 336 } // end namespace objcopy 337 } // end namespace llvm 338