1*81ad6265SDimitry Andric //===- COFFObjcopy.cpp ----------------------------------------------------===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric 9*81ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFObjcopy.h" 10*81ad6265SDimitry Andric #include "COFFObject.h" 11*81ad6265SDimitry Andric #include "COFFReader.h" 12*81ad6265SDimitry Andric #include "COFFWriter.h" 13*81ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFConfig.h" 14*81ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h" 15*81ad6265SDimitry Andric 16*81ad6265SDimitry Andric #include "llvm/Object/Binary.h" 17*81ad6265SDimitry Andric #include "llvm/Object/COFF.h" 18*81ad6265SDimitry Andric #include "llvm/Support/CRC.h" 19*81ad6265SDimitry Andric #include "llvm/Support/Errc.h" 20*81ad6265SDimitry Andric #include "llvm/Support/Path.h" 21*81ad6265SDimitry Andric #include <cassert> 22*81ad6265SDimitry Andric 23*81ad6265SDimitry Andric namespace llvm { 24*81ad6265SDimitry Andric namespace objcopy { 25*81ad6265SDimitry Andric namespace coff { 26*81ad6265SDimitry Andric 27*81ad6265SDimitry Andric using namespace object; 28*81ad6265SDimitry Andric using namespace COFF; 29*81ad6265SDimitry Andric 30*81ad6265SDimitry Andric static bool isDebugSection(const Section &Sec) { 31*81ad6265SDimitry Andric return Sec.Name.startswith(".debug"); 32*81ad6265SDimitry Andric } 33*81ad6265SDimitry Andric 34*81ad6265SDimitry Andric static uint64_t getNextRVA(const Object &Obj) { 35*81ad6265SDimitry Andric if (Obj.getSections().empty()) 36*81ad6265SDimitry Andric return 0; 37*81ad6265SDimitry Andric const Section &Last = Obj.getSections().back(); 38*81ad6265SDimitry Andric return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize, 39*81ad6265SDimitry Andric Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1); 40*81ad6265SDimitry Andric } 41*81ad6265SDimitry Andric 42*81ad6265SDimitry Andric static Expected<std::vector<uint8_t>> 43*81ad6265SDimitry Andric createGnuDebugLinkSectionContents(StringRef File) { 44*81ad6265SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr = 45*81ad6265SDimitry Andric MemoryBuffer::getFile(File); 46*81ad6265SDimitry Andric if (!LinkTargetOrErr) 47*81ad6265SDimitry Andric return createFileError(File, LinkTargetOrErr.getError()); 48*81ad6265SDimitry Andric auto LinkTarget = std::move(*LinkTargetOrErr); 49*81ad6265SDimitry Andric uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer())); 50*81ad6265SDimitry Andric 51*81ad6265SDimitry Andric StringRef FileName = sys::path::filename(File); 52*81ad6265SDimitry Andric size_t CRCPos = alignTo(FileName.size() + 1, 4); 53*81ad6265SDimitry Andric std::vector<uint8_t> Data(CRCPos + 4); 54*81ad6265SDimitry Andric memcpy(Data.data(), FileName.data(), FileName.size()); 55*81ad6265SDimitry Andric support::endian::write32le(Data.data() + CRCPos, CRC32); 56*81ad6265SDimitry Andric return Data; 57*81ad6265SDimitry Andric } 58*81ad6265SDimitry Andric 59*81ad6265SDimitry Andric // Adds named section with given contents to the object. 60*81ad6265SDimitry Andric static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents, 61*81ad6265SDimitry Andric uint32_t Characteristics) { 62*81ad6265SDimitry Andric bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | 63*81ad6265SDimitry Andric IMAGE_SCN_MEM_WRITE); 64*81ad6265SDimitry Andric 65*81ad6265SDimitry Andric Section Sec; 66*81ad6265SDimitry Andric Sec.setOwnedContents(Contents); 67*81ad6265SDimitry Andric Sec.Name = Name; 68*81ad6265SDimitry Andric Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u; 69*81ad6265SDimitry Andric Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u; 70*81ad6265SDimitry Andric Sec.Header.SizeOfRawData = 71*81ad6265SDimitry Andric NeedVA ? alignTo(Sec.Header.VirtualSize, 72*81ad6265SDimitry Andric Obj.IsPE ? Obj.PeHeader.FileAlignment : 1) 73*81ad6265SDimitry Andric : Sec.getContents().size(); 74*81ad6265SDimitry Andric // Sec.Header.PointerToRawData is filled in by the writer. 75*81ad6265SDimitry Andric Sec.Header.PointerToRelocations = 0; 76*81ad6265SDimitry Andric Sec.Header.PointerToLinenumbers = 0; 77*81ad6265SDimitry Andric // Sec.Header.NumberOfRelocations is filled in by the writer. 78*81ad6265SDimitry Andric Sec.Header.NumberOfLinenumbers = 0; 79*81ad6265SDimitry Andric Sec.Header.Characteristics = Characteristics; 80*81ad6265SDimitry Andric 81*81ad6265SDimitry Andric Obj.addSections(Sec); 82*81ad6265SDimitry Andric } 83*81ad6265SDimitry Andric 84*81ad6265SDimitry Andric static Error addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) { 85*81ad6265SDimitry Andric Expected<std::vector<uint8_t>> Contents = 86*81ad6265SDimitry Andric createGnuDebugLinkSectionContents(DebugLinkFile); 87*81ad6265SDimitry Andric if (!Contents) 88*81ad6265SDimitry Andric return Contents.takeError(); 89*81ad6265SDimitry Andric 90*81ad6265SDimitry Andric addSection(Obj, ".gnu_debuglink", *Contents, 91*81ad6265SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 92*81ad6265SDimitry Andric IMAGE_SCN_MEM_DISCARDABLE); 93*81ad6265SDimitry Andric 94*81ad6265SDimitry Andric return Error::success(); 95*81ad6265SDimitry Andric } 96*81ad6265SDimitry Andric 97*81ad6265SDimitry Andric static uint32_t flagsToCharacteristics(SectionFlag AllFlags, uint32_t OldChar) { 98*81ad6265SDimitry Andric // Need to preserve alignment flags. 99*81ad6265SDimitry Andric const uint32_t PreserveMask = 100*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES | 101*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES | 102*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES | 103*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES | 104*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES | 105*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES | 106*81ad6265SDimitry Andric IMAGE_SCN_ALIGN_8192BYTES; 107*81ad6265SDimitry Andric 108*81ad6265SDimitry Andric // Setup new section characteristics based on the flags provided in command 109*81ad6265SDimitry Andric // line. 110*81ad6265SDimitry Andric uint32_t NewCharacteristics = (OldChar & PreserveMask) | IMAGE_SCN_MEM_READ; 111*81ad6265SDimitry Andric 112*81ad6265SDimitry Andric if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad)) 113*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; 114*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecNoload) 115*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; 116*81ad6265SDimitry Andric if (!(AllFlags & SectionFlag::SecReadonly)) 117*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_MEM_WRITE; 118*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecDebug) 119*81ad6265SDimitry Andric NewCharacteristics |= 120*81ad6265SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE; 121*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecCode) 122*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; 123*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecData) 124*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 125*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecShare) 126*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_MEM_SHARED; 127*81ad6265SDimitry Andric if (AllFlags & SectionFlag::SecExclude) 128*81ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; 129*81ad6265SDimitry Andric 130*81ad6265SDimitry Andric return NewCharacteristics; 131*81ad6265SDimitry Andric } 132*81ad6265SDimitry Andric 133*81ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config, 134*81ad6265SDimitry Andric const COFFConfig &COFFConfig, Object &Obj) { 135*81ad6265SDimitry Andric // Perform the actual section removals. 136*81ad6265SDimitry Andric Obj.removeSections([&Config](const Section &Sec) { 137*81ad6265SDimitry Andric // Contrary to --only-keep-debug, --only-section fully removes sections that 138*81ad6265SDimitry Andric // aren't mentioned. 139*81ad6265SDimitry Andric if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name)) 140*81ad6265SDimitry Andric return true; 141*81ad6265SDimitry Andric 142*81ad6265SDimitry Andric if (Config.StripDebug || Config.StripAll || Config.StripAllGNU || 143*81ad6265SDimitry Andric Config.DiscardMode == DiscardType::All || Config.StripUnneeded) { 144*81ad6265SDimitry Andric if (isDebugSection(Sec) && 145*81ad6265SDimitry Andric (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) 146*81ad6265SDimitry Andric return true; 147*81ad6265SDimitry Andric } 148*81ad6265SDimitry Andric 149*81ad6265SDimitry Andric if (Config.ToRemove.matches(Sec.Name)) 150*81ad6265SDimitry Andric return true; 151*81ad6265SDimitry Andric 152*81ad6265SDimitry Andric return false; 153*81ad6265SDimitry Andric }); 154*81ad6265SDimitry Andric 155*81ad6265SDimitry Andric if (Config.OnlyKeepDebug) { 156*81ad6265SDimitry Andric // For --only-keep-debug, we keep all other sections, but remove their 157*81ad6265SDimitry Andric // content. The VirtualSize field in the section header is kept intact. 158*81ad6265SDimitry Andric Obj.truncateSections([](const Section &Sec) { 159*81ad6265SDimitry Andric return !isDebugSection(Sec) && Sec.Name != ".buildid" && 160*81ad6265SDimitry Andric ((Sec.Header.Characteristics & 161*81ad6265SDimitry Andric (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0); 162*81ad6265SDimitry Andric }); 163*81ad6265SDimitry Andric } 164*81ad6265SDimitry Andric 165*81ad6265SDimitry Andric // StripAll removes all symbols and thus also removes all relocations. 166*81ad6265SDimitry Andric if (Config.StripAll || Config.StripAllGNU) 167*81ad6265SDimitry Andric for (Section &Sec : Obj.getMutableSections()) 168*81ad6265SDimitry Andric Sec.Relocs.clear(); 169*81ad6265SDimitry Andric 170*81ad6265SDimitry Andric // If we need to do per-symbol removals, initialize the Referenced field. 171*81ad6265SDimitry Andric if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All || 172*81ad6265SDimitry Andric !Config.SymbolsToRemove.empty()) 173*81ad6265SDimitry Andric if (Error E = Obj.markSymbols()) 174*81ad6265SDimitry Andric return E; 175*81ad6265SDimitry Andric 176*81ad6265SDimitry Andric for (Symbol &Sym : Obj.getMutableSymbols()) { 177*81ad6265SDimitry Andric auto I = Config.SymbolsToRename.find(Sym.Name); 178*81ad6265SDimitry Andric if (I != Config.SymbolsToRename.end()) 179*81ad6265SDimitry Andric Sym.Name = I->getValue(); 180*81ad6265SDimitry Andric } 181*81ad6265SDimitry Andric 182*81ad6265SDimitry Andric auto ToRemove = [&](const Symbol &Sym) -> Expected<bool> { 183*81ad6265SDimitry Andric // For StripAll, all relocations have been stripped and we remove all 184*81ad6265SDimitry Andric // symbols. 185*81ad6265SDimitry Andric if (Config.StripAll || Config.StripAllGNU) 186*81ad6265SDimitry Andric return true; 187*81ad6265SDimitry Andric 188*81ad6265SDimitry Andric if (Config.SymbolsToRemove.matches(Sym.Name)) { 189*81ad6265SDimitry Andric // Explicitly removing a referenced symbol is an error. 190*81ad6265SDimitry Andric if (Sym.Referenced) 191*81ad6265SDimitry Andric return createStringError( 192*81ad6265SDimitry Andric llvm::errc::invalid_argument, 193*81ad6265SDimitry Andric "'" + Config.OutputFilename + "': not stripping symbol '" + 194*81ad6265SDimitry Andric Sym.Name.str() + "' because it is named in a relocation"); 195*81ad6265SDimitry Andric return true; 196*81ad6265SDimitry Andric } 197*81ad6265SDimitry Andric 198*81ad6265SDimitry Andric if (!Sym.Referenced) { 199*81ad6265SDimitry Andric // With --strip-unneeded, GNU objcopy removes all unreferenced local 200*81ad6265SDimitry Andric // symbols, and any unreferenced undefined external. 201*81ad6265SDimitry Andric // With --strip-unneeded-symbol we strip only specific unreferenced 202*81ad6265SDimitry Andric // local symbol instead of removing all of such. 203*81ad6265SDimitry Andric if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC || 204*81ad6265SDimitry Andric Sym.Sym.SectionNumber == 0) 205*81ad6265SDimitry Andric if (Config.StripUnneeded || 206*81ad6265SDimitry Andric Config.UnneededSymbolsToRemove.matches(Sym.Name)) 207*81ad6265SDimitry Andric return true; 208*81ad6265SDimitry Andric 209*81ad6265SDimitry Andric // GNU objcopy keeps referenced local symbols and external symbols 210*81ad6265SDimitry Andric // if --discard-all is set, similar to what --strip-unneeded does, 211*81ad6265SDimitry Andric // but undefined local symbols are kept when --discard-all is set. 212*81ad6265SDimitry Andric if (Config.DiscardMode == DiscardType::All && 213*81ad6265SDimitry Andric Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC && 214*81ad6265SDimitry Andric Sym.Sym.SectionNumber != 0) 215*81ad6265SDimitry Andric return true; 216*81ad6265SDimitry Andric } 217*81ad6265SDimitry Andric 218*81ad6265SDimitry Andric return false; 219*81ad6265SDimitry Andric }; 220*81ad6265SDimitry Andric 221*81ad6265SDimitry Andric // Actually do removals of symbols. 222*81ad6265SDimitry Andric if (Error Err = Obj.removeSymbols(ToRemove)) 223*81ad6265SDimitry Andric return Err; 224*81ad6265SDimitry Andric 225*81ad6265SDimitry Andric if (!Config.SetSectionFlags.empty()) 226*81ad6265SDimitry Andric for (Section &Sec : Obj.getMutableSections()) { 227*81ad6265SDimitry Andric const auto It = Config.SetSectionFlags.find(Sec.Name); 228*81ad6265SDimitry Andric if (It != Config.SetSectionFlags.end()) 229*81ad6265SDimitry Andric Sec.Header.Characteristics = flagsToCharacteristics( 230*81ad6265SDimitry Andric It->second.NewFlags, Sec.Header.Characteristics); 231*81ad6265SDimitry Andric } 232*81ad6265SDimitry Andric 233*81ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.AddSection) { 234*81ad6265SDimitry Andric uint32_t Characteristics; 235*81ad6265SDimitry Andric const auto It = Config.SetSectionFlags.find(NewSection.SectionName); 236*81ad6265SDimitry Andric if (It != Config.SetSectionFlags.end()) 237*81ad6265SDimitry Andric Characteristics = flagsToCharacteristics(It->second.NewFlags, 0); 238*81ad6265SDimitry Andric else 239*81ad6265SDimitry Andric Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES; 240*81ad6265SDimitry Andric 241*81ad6265SDimitry Andric addSection(Obj, NewSection.SectionName, 242*81ad6265SDimitry Andric makeArrayRef(reinterpret_cast<const uint8_t *>( 243*81ad6265SDimitry Andric NewSection.SectionData->getBufferStart()), 244*81ad6265SDimitry Andric NewSection.SectionData->getBufferSize()), 245*81ad6265SDimitry Andric Characteristics); 246*81ad6265SDimitry Andric } 247*81ad6265SDimitry Andric 248*81ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.UpdateSection) { 249*81ad6265SDimitry Andric auto It = llvm::find_if(Obj.getMutableSections(), [&](auto &Sec) { 250*81ad6265SDimitry Andric return Sec.Name == NewSection.SectionName; 251*81ad6265SDimitry Andric }); 252*81ad6265SDimitry Andric if (It == Obj.getMutableSections().end()) 253*81ad6265SDimitry Andric return createStringError(errc::invalid_argument, 254*81ad6265SDimitry Andric "could not find section with name '%s'", 255*81ad6265SDimitry Andric NewSection.SectionName.str().c_str()); 256*81ad6265SDimitry Andric size_t ContentSize = It->getContents().size(); 257*81ad6265SDimitry Andric if (!ContentSize) 258*81ad6265SDimitry Andric return createStringError( 259*81ad6265SDimitry Andric errc::invalid_argument, 260*81ad6265SDimitry Andric "section '%s' cannot be updated because it does not have contents", 261*81ad6265SDimitry Andric NewSection.SectionName.str().c_str()); 262*81ad6265SDimitry Andric if (ContentSize < NewSection.SectionData->getBufferSize()) 263*81ad6265SDimitry Andric return createStringError( 264*81ad6265SDimitry Andric errc::invalid_argument, 265*81ad6265SDimitry Andric "new section cannot be larger than previous section"); 266*81ad6265SDimitry Andric It->setOwnedContents({NewSection.SectionData->getBufferStart(), 267*81ad6265SDimitry Andric NewSection.SectionData->getBufferEnd()}); 268*81ad6265SDimitry Andric } 269*81ad6265SDimitry Andric 270*81ad6265SDimitry Andric if (!Config.AddGnuDebugLink.empty()) 271*81ad6265SDimitry Andric if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) 272*81ad6265SDimitry Andric return E; 273*81ad6265SDimitry Andric 274*81ad6265SDimitry Andric if (COFFConfig.Subsystem || COFFConfig.MajorSubsystemVersion || 275*81ad6265SDimitry Andric COFFConfig.MinorSubsystemVersion) { 276*81ad6265SDimitry Andric if (!Obj.IsPE) 277*81ad6265SDimitry Andric return createStringError( 278*81ad6265SDimitry Andric errc::invalid_argument, 279*81ad6265SDimitry Andric "'" + Config.OutputFilename + 280*81ad6265SDimitry Andric "': unable to set subsystem on a relocatable object file"); 281*81ad6265SDimitry Andric if (COFFConfig.Subsystem) 282*81ad6265SDimitry Andric Obj.PeHeader.Subsystem = *COFFConfig.Subsystem; 283*81ad6265SDimitry Andric if (COFFConfig.MajorSubsystemVersion) 284*81ad6265SDimitry Andric Obj.PeHeader.MajorSubsystemVersion = *COFFConfig.MajorSubsystemVersion; 285*81ad6265SDimitry Andric if (COFFConfig.MinorSubsystemVersion) 286*81ad6265SDimitry Andric Obj.PeHeader.MinorSubsystemVersion = *COFFConfig.MinorSubsystemVersion; 287*81ad6265SDimitry Andric } 288*81ad6265SDimitry Andric 289*81ad6265SDimitry Andric return Error::success(); 290*81ad6265SDimitry Andric } 291*81ad6265SDimitry Andric 292*81ad6265SDimitry Andric Error executeObjcopyOnBinary(const CommonConfig &Config, 293*81ad6265SDimitry Andric const COFFConfig &COFFConfig, COFFObjectFile &In, 294*81ad6265SDimitry Andric raw_ostream &Out) { 295*81ad6265SDimitry Andric COFFReader Reader(In); 296*81ad6265SDimitry Andric Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create(); 297*81ad6265SDimitry Andric if (!ObjOrErr) 298*81ad6265SDimitry Andric return createFileError(Config.InputFilename, ObjOrErr.takeError()); 299*81ad6265SDimitry Andric Object *Obj = ObjOrErr->get(); 300*81ad6265SDimitry Andric assert(Obj && "Unable to deserialize COFF object"); 301*81ad6265SDimitry Andric if (Error E = handleArgs(Config, COFFConfig, *Obj)) 302*81ad6265SDimitry Andric return createFileError(Config.InputFilename, std::move(E)); 303*81ad6265SDimitry Andric COFFWriter Writer(*Obj, Out); 304*81ad6265SDimitry Andric if (Error E = Writer.write()) 305*81ad6265SDimitry Andric return createFileError(Config.OutputFilename, std::move(E)); 306*81ad6265SDimitry Andric return Error::success(); 307*81ad6265SDimitry Andric } 308*81ad6265SDimitry Andric 309*81ad6265SDimitry Andric } // end namespace coff 310*81ad6265SDimitry Andric } // end namespace objcopy 311*81ad6265SDimitry Andric } // end namespace llvm 312