181ad6265SDimitry Andric //===- COFFObjcopy.cpp ----------------------------------------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFObjcopy.h" 1081ad6265SDimitry Andric #include "COFFObject.h" 1181ad6265SDimitry Andric #include "COFFReader.h" 1281ad6265SDimitry Andric #include "COFFWriter.h" 1381ad6265SDimitry Andric #include "llvm/ObjCopy/COFF/COFFConfig.h" 1481ad6265SDimitry Andric #include "llvm/ObjCopy/CommonConfig.h" 1581ad6265SDimitry Andric 1681ad6265SDimitry Andric #include "llvm/Object/Binary.h" 1781ad6265SDimitry Andric #include "llvm/Object/COFF.h" 1881ad6265SDimitry Andric #include "llvm/Support/CRC.h" 1981ad6265SDimitry Andric #include "llvm/Support/Errc.h" 2081ad6265SDimitry Andric #include "llvm/Support/Path.h" 2181ad6265SDimitry Andric #include <cassert> 2281ad6265SDimitry Andric 2381ad6265SDimitry Andric namespace llvm { 2481ad6265SDimitry Andric namespace objcopy { 2581ad6265SDimitry Andric namespace coff { 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric using namespace object; 2881ad6265SDimitry Andric using namespace COFF; 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric static bool isDebugSection(const Section &Sec) { 3181ad6265SDimitry Andric return Sec.Name.startswith(".debug"); 3281ad6265SDimitry Andric } 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric static uint64_t getNextRVA(const Object &Obj) { 3581ad6265SDimitry Andric if (Obj.getSections().empty()) 3681ad6265SDimitry Andric return 0; 3781ad6265SDimitry Andric const Section &Last = Obj.getSections().back(); 3881ad6265SDimitry Andric return alignTo(Last.Header.VirtualAddress + Last.Header.VirtualSize, 3981ad6265SDimitry Andric Obj.IsPE ? Obj.PeHeader.SectionAlignment : 1); 4081ad6265SDimitry Andric } 4181ad6265SDimitry Andric 4281ad6265SDimitry Andric static Expected<std::vector<uint8_t>> 4381ad6265SDimitry Andric createGnuDebugLinkSectionContents(StringRef File) { 4481ad6265SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> LinkTargetOrErr = 4581ad6265SDimitry Andric MemoryBuffer::getFile(File); 4681ad6265SDimitry Andric if (!LinkTargetOrErr) 4781ad6265SDimitry Andric return createFileError(File, LinkTargetOrErr.getError()); 4881ad6265SDimitry Andric auto LinkTarget = std::move(*LinkTargetOrErr); 4981ad6265SDimitry Andric uint32_t CRC32 = llvm::crc32(arrayRefFromStringRef(LinkTarget->getBuffer())); 5081ad6265SDimitry Andric 5181ad6265SDimitry Andric StringRef FileName = sys::path::filename(File); 5281ad6265SDimitry Andric size_t CRCPos = alignTo(FileName.size() + 1, 4); 5381ad6265SDimitry Andric std::vector<uint8_t> Data(CRCPos + 4); 5481ad6265SDimitry Andric memcpy(Data.data(), FileName.data(), FileName.size()); 5581ad6265SDimitry Andric support::endian::write32le(Data.data() + CRCPos, CRC32); 5681ad6265SDimitry Andric return Data; 5781ad6265SDimitry Andric } 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric // Adds named section with given contents to the object. 6081ad6265SDimitry Andric static void addSection(Object &Obj, StringRef Name, ArrayRef<uint8_t> Contents, 6181ad6265SDimitry Andric uint32_t Characteristics) { 6281ad6265SDimitry Andric bool NeedVA = Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | 6381ad6265SDimitry Andric IMAGE_SCN_MEM_WRITE); 6481ad6265SDimitry Andric 6581ad6265SDimitry Andric Section Sec; 6681ad6265SDimitry Andric Sec.setOwnedContents(Contents); 6781ad6265SDimitry Andric Sec.Name = Name; 6881ad6265SDimitry Andric Sec.Header.VirtualSize = NeedVA ? Sec.getContents().size() : 0u; 6981ad6265SDimitry Andric Sec.Header.VirtualAddress = NeedVA ? getNextRVA(Obj) : 0u; 7081ad6265SDimitry Andric Sec.Header.SizeOfRawData = 7181ad6265SDimitry Andric NeedVA ? alignTo(Sec.Header.VirtualSize, 7281ad6265SDimitry Andric Obj.IsPE ? Obj.PeHeader.FileAlignment : 1) 7381ad6265SDimitry Andric : Sec.getContents().size(); 7481ad6265SDimitry Andric // Sec.Header.PointerToRawData is filled in by the writer. 7581ad6265SDimitry Andric Sec.Header.PointerToRelocations = 0; 7681ad6265SDimitry Andric Sec.Header.PointerToLinenumbers = 0; 7781ad6265SDimitry Andric // Sec.Header.NumberOfRelocations is filled in by the writer. 7881ad6265SDimitry Andric Sec.Header.NumberOfLinenumbers = 0; 7981ad6265SDimitry Andric Sec.Header.Characteristics = Characteristics; 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric Obj.addSections(Sec); 8281ad6265SDimitry Andric } 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric static Error addGnuDebugLink(Object &Obj, StringRef DebugLinkFile) { 8581ad6265SDimitry Andric Expected<std::vector<uint8_t>> Contents = 8681ad6265SDimitry Andric createGnuDebugLinkSectionContents(DebugLinkFile); 8781ad6265SDimitry Andric if (!Contents) 8881ad6265SDimitry Andric return Contents.takeError(); 8981ad6265SDimitry Andric 9081ad6265SDimitry Andric addSection(Obj, ".gnu_debuglink", *Contents, 9181ad6265SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | 9281ad6265SDimitry Andric IMAGE_SCN_MEM_DISCARDABLE); 9381ad6265SDimitry Andric 9481ad6265SDimitry Andric return Error::success(); 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric 9781ad6265SDimitry Andric static uint32_t flagsToCharacteristics(SectionFlag AllFlags, uint32_t OldChar) { 9881ad6265SDimitry Andric // Need to preserve alignment flags. 9981ad6265SDimitry Andric const uint32_t PreserveMask = 10081ad6265SDimitry Andric IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_ALIGN_4BYTES | 10181ad6265SDimitry Andric IMAGE_SCN_ALIGN_8BYTES | IMAGE_SCN_ALIGN_16BYTES | 10281ad6265SDimitry Andric IMAGE_SCN_ALIGN_32BYTES | IMAGE_SCN_ALIGN_64BYTES | 10381ad6265SDimitry Andric IMAGE_SCN_ALIGN_128BYTES | IMAGE_SCN_ALIGN_256BYTES | 10481ad6265SDimitry Andric IMAGE_SCN_ALIGN_512BYTES | IMAGE_SCN_ALIGN_1024BYTES | 10581ad6265SDimitry Andric IMAGE_SCN_ALIGN_2048BYTES | IMAGE_SCN_ALIGN_4096BYTES | 10681ad6265SDimitry Andric IMAGE_SCN_ALIGN_8192BYTES; 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric // Setup new section characteristics based on the flags provided in command 10981ad6265SDimitry Andric // line. 11081ad6265SDimitry Andric uint32_t NewCharacteristics = (OldChar & PreserveMask) | IMAGE_SCN_MEM_READ; 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric if ((AllFlags & SectionFlag::SecAlloc) && !(AllFlags & SectionFlag::SecLoad)) 11381ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; 11481ad6265SDimitry Andric if (AllFlags & SectionFlag::SecNoload) 11581ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; 11681ad6265SDimitry Andric if (!(AllFlags & SectionFlag::SecReadonly)) 11781ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_MEM_WRITE; 11881ad6265SDimitry Andric if (AllFlags & SectionFlag::SecDebug) 11981ad6265SDimitry Andric NewCharacteristics |= 12081ad6265SDimitry Andric IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE; 12181ad6265SDimitry Andric if (AllFlags & SectionFlag::SecCode) 12281ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; 12381ad6265SDimitry Andric if (AllFlags & SectionFlag::SecData) 12481ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; 12581ad6265SDimitry Andric if (AllFlags & SectionFlag::SecShare) 12681ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_MEM_SHARED; 12781ad6265SDimitry Andric if (AllFlags & SectionFlag::SecExclude) 12881ad6265SDimitry Andric NewCharacteristics |= IMAGE_SCN_LNK_REMOVE; 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric return NewCharacteristics; 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric static Error handleArgs(const CommonConfig &Config, 13481ad6265SDimitry Andric const COFFConfig &COFFConfig, Object &Obj) { 13581ad6265SDimitry Andric // Perform the actual section removals. 13681ad6265SDimitry Andric Obj.removeSections([&Config](const Section &Sec) { 13781ad6265SDimitry Andric // Contrary to --only-keep-debug, --only-section fully removes sections that 13881ad6265SDimitry Andric // aren't mentioned. 13981ad6265SDimitry Andric if (!Config.OnlySection.empty() && !Config.OnlySection.matches(Sec.Name)) 14081ad6265SDimitry Andric return true; 14181ad6265SDimitry Andric 14281ad6265SDimitry Andric if (Config.StripDebug || Config.StripAll || Config.StripAllGNU || 14381ad6265SDimitry Andric Config.DiscardMode == DiscardType::All || Config.StripUnneeded) { 14481ad6265SDimitry Andric if (isDebugSection(Sec) && 14581ad6265SDimitry Andric (Sec.Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0) 14681ad6265SDimitry Andric return true; 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric 14981ad6265SDimitry Andric if (Config.ToRemove.matches(Sec.Name)) 15081ad6265SDimitry Andric return true; 15181ad6265SDimitry Andric 15281ad6265SDimitry Andric return false; 15381ad6265SDimitry Andric }); 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric if (Config.OnlyKeepDebug) { 15681ad6265SDimitry Andric // For --only-keep-debug, we keep all other sections, but remove their 15781ad6265SDimitry Andric // content. The VirtualSize field in the section header is kept intact. 15881ad6265SDimitry Andric Obj.truncateSections([](const Section &Sec) { 15981ad6265SDimitry Andric return !isDebugSection(Sec) && Sec.Name != ".buildid" && 16081ad6265SDimitry Andric ((Sec.Header.Characteristics & 16181ad6265SDimitry Andric (IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA)) != 0); 16281ad6265SDimitry Andric }); 16381ad6265SDimitry Andric } 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric // StripAll removes all symbols and thus also removes all relocations. 16681ad6265SDimitry Andric if (Config.StripAll || Config.StripAllGNU) 16781ad6265SDimitry Andric for (Section &Sec : Obj.getMutableSections()) 16881ad6265SDimitry Andric Sec.Relocs.clear(); 16981ad6265SDimitry Andric 17081ad6265SDimitry Andric // If we need to do per-symbol removals, initialize the Referenced field. 17181ad6265SDimitry Andric if (Config.StripUnneeded || Config.DiscardMode == DiscardType::All || 17281ad6265SDimitry Andric !Config.SymbolsToRemove.empty()) 17381ad6265SDimitry Andric if (Error E = Obj.markSymbols()) 17481ad6265SDimitry Andric return E; 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric for (Symbol &Sym : Obj.getMutableSymbols()) { 17781ad6265SDimitry Andric auto I = Config.SymbolsToRename.find(Sym.Name); 17881ad6265SDimitry Andric if (I != Config.SymbolsToRename.end()) 17981ad6265SDimitry Andric Sym.Name = I->getValue(); 18081ad6265SDimitry Andric } 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric auto ToRemove = [&](const Symbol &Sym) -> Expected<bool> { 18381ad6265SDimitry Andric // For StripAll, all relocations have been stripped and we remove all 18481ad6265SDimitry Andric // symbols. 18581ad6265SDimitry Andric if (Config.StripAll || Config.StripAllGNU) 18681ad6265SDimitry Andric return true; 18781ad6265SDimitry Andric 18881ad6265SDimitry Andric if (Config.SymbolsToRemove.matches(Sym.Name)) { 18981ad6265SDimitry Andric // Explicitly removing a referenced symbol is an error. 19081ad6265SDimitry Andric if (Sym.Referenced) 19181ad6265SDimitry Andric return createStringError( 19281ad6265SDimitry Andric llvm::errc::invalid_argument, 19381ad6265SDimitry Andric "'" + Config.OutputFilename + "': not stripping symbol '" + 19481ad6265SDimitry Andric Sym.Name.str() + "' because it is named in a relocation"); 19581ad6265SDimitry Andric return true; 19681ad6265SDimitry Andric } 19781ad6265SDimitry Andric 19881ad6265SDimitry Andric if (!Sym.Referenced) { 19981ad6265SDimitry Andric // With --strip-unneeded, GNU objcopy removes all unreferenced local 20081ad6265SDimitry Andric // symbols, and any unreferenced undefined external. 20181ad6265SDimitry Andric // With --strip-unneeded-symbol we strip only specific unreferenced 20281ad6265SDimitry Andric // local symbol instead of removing all of such. 20381ad6265SDimitry Andric if (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC || 20481ad6265SDimitry Andric Sym.Sym.SectionNumber == 0) 20581ad6265SDimitry Andric if (Config.StripUnneeded || 20681ad6265SDimitry Andric Config.UnneededSymbolsToRemove.matches(Sym.Name)) 20781ad6265SDimitry Andric return true; 20881ad6265SDimitry Andric 20981ad6265SDimitry Andric // GNU objcopy keeps referenced local symbols and external symbols 21081ad6265SDimitry Andric // if --discard-all is set, similar to what --strip-unneeded does, 21181ad6265SDimitry Andric // but undefined local symbols are kept when --discard-all is set. 21281ad6265SDimitry Andric if (Config.DiscardMode == DiscardType::All && 21381ad6265SDimitry Andric Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC && 21481ad6265SDimitry Andric Sym.Sym.SectionNumber != 0) 21581ad6265SDimitry Andric return true; 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric return false; 21981ad6265SDimitry Andric }; 22081ad6265SDimitry Andric 22181ad6265SDimitry Andric // Actually do removals of symbols. 22281ad6265SDimitry Andric if (Error Err = Obj.removeSymbols(ToRemove)) 22381ad6265SDimitry Andric return Err; 22481ad6265SDimitry Andric 22581ad6265SDimitry Andric if (!Config.SetSectionFlags.empty()) 22681ad6265SDimitry Andric for (Section &Sec : Obj.getMutableSections()) { 22781ad6265SDimitry Andric const auto It = Config.SetSectionFlags.find(Sec.Name); 22881ad6265SDimitry Andric if (It != Config.SetSectionFlags.end()) 22981ad6265SDimitry Andric Sec.Header.Characteristics = flagsToCharacteristics( 23081ad6265SDimitry Andric It->second.NewFlags, Sec.Header.Characteristics); 23181ad6265SDimitry Andric } 23281ad6265SDimitry Andric 23381ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.AddSection) { 23481ad6265SDimitry Andric uint32_t Characteristics; 23581ad6265SDimitry Andric const auto It = Config.SetSectionFlags.find(NewSection.SectionName); 23681ad6265SDimitry Andric if (It != Config.SetSectionFlags.end()) 23781ad6265SDimitry Andric Characteristics = flagsToCharacteristics(It->second.NewFlags, 0); 23881ad6265SDimitry Andric else 23981ad6265SDimitry Andric Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES; 24081ad6265SDimitry Andric 24181ad6265SDimitry Andric addSection(Obj, NewSection.SectionName, 242*bdd1243dSDimitry Andric ArrayRef(reinterpret_cast<const uint8_t *>( 24381ad6265SDimitry Andric NewSection.SectionData->getBufferStart()), 24481ad6265SDimitry Andric NewSection.SectionData->getBufferSize()), 24581ad6265SDimitry Andric Characteristics); 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric for (const NewSectionInfo &NewSection : Config.UpdateSection) { 24981ad6265SDimitry Andric auto It = llvm::find_if(Obj.getMutableSections(), [&](auto &Sec) { 25081ad6265SDimitry Andric return Sec.Name == NewSection.SectionName; 25181ad6265SDimitry Andric }); 25281ad6265SDimitry Andric if (It == Obj.getMutableSections().end()) 25381ad6265SDimitry Andric return createStringError(errc::invalid_argument, 25481ad6265SDimitry Andric "could not find section with name '%s'", 25581ad6265SDimitry Andric NewSection.SectionName.str().c_str()); 25681ad6265SDimitry Andric size_t ContentSize = It->getContents().size(); 25781ad6265SDimitry Andric if (!ContentSize) 25881ad6265SDimitry Andric return createStringError( 25981ad6265SDimitry Andric errc::invalid_argument, 26081ad6265SDimitry Andric "section '%s' cannot be updated because it does not have contents", 26181ad6265SDimitry Andric NewSection.SectionName.str().c_str()); 26281ad6265SDimitry Andric if (ContentSize < NewSection.SectionData->getBufferSize()) 26381ad6265SDimitry Andric return createStringError( 26481ad6265SDimitry Andric errc::invalid_argument, 26581ad6265SDimitry Andric "new section cannot be larger than previous section"); 26681ad6265SDimitry Andric It->setOwnedContents({NewSection.SectionData->getBufferStart(), 26781ad6265SDimitry Andric NewSection.SectionData->getBufferEnd()}); 26881ad6265SDimitry Andric } 26981ad6265SDimitry Andric 27081ad6265SDimitry Andric if (!Config.AddGnuDebugLink.empty()) 27181ad6265SDimitry Andric if (Error E = addGnuDebugLink(Obj, Config.AddGnuDebugLink)) 27281ad6265SDimitry Andric return E; 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric if (COFFConfig.Subsystem || COFFConfig.MajorSubsystemVersion || 27581ad6265SDimitry Andric COFFConfig.MinorSubsystemVersion) { 27681ad6265SDimitry Andric if (!Obj.IsPE) 27781ad6265SDimitry Andric return createStringError( 27881ad6265SDimitry Andric errc::invalid_argument, 27981ad6265SDimitry Andric "'" + Config.OutputFilename + 28081ad6265SDimitry Andric "': unable to set subsystem on a relocatable object file"); 28181ad6265SDimitry Andric if (COFFConfig.Subsystem) 28281ad6265SDimitry Andric Obj.PeHeader.Subsystem = *COFFConfig.Subsystem; 28381ad6265SDimitry Andric if (COFFConfig.MajorSubsystemVersion) 28481ad6265SDimitry Andric Obj.PeHeader.MajorSubsystemVersion = *COFFConfig.MajorSubsystemVersion; 28581ad6265SDimitry Andric if (COFFConfig.MinorSubsystemVersion) 28681ad6265SDimitry Andric Obj.PeHeader.MinorSubsystemVersion = *COFFConfig.MinorSubsystemVersion; 28781ad6265SDimitry Andric } 28881ad6265SDimitry Andric 28981ad6265SDimitry Andric return Error::success(); 29081ad6265SDimitry Andric } 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric Error executeObjcopyOnBinary(const CommonConfig &Config, 29381ad6265SDimitry Andric const COFFConfig &COFFConfig, COFFObjectFile &In, 29481ad6265SDimitry Andric raw_ostream &Out) { 29581ad6265SDimitry Andric COFFReader Reader(In); 29681ad6265SDimitry Andric Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create(); 29781ad6265SDimitry Andric if (!ObjOrErr) 29881ad6265SDimitry Andric return createFileError(Config.InputFilename, ObjOrErr.takeError()); 29981ad6265SDimitry Andric Object *Obj = ObjOrErr->get(); 30081ad6265SDimitry Andric assert(Obj && "Unable to deserialize COFF object"); 30181ad6265SDimitry Andric if (Error E = handleArgs(Config, COFFConfig, *Obj)) 30281ad6265SDimitry Andric return createFileError(Config.InputFilename, std::move(E)); 30381ad6265SDimitry Andric COFFWriter Writer(*Obj, Out); 30481ad6265SDimitry Andric if (Error E = Writer.write()) 30581ad6265SDimitry Andric return createFileError(Config.OutputFilename, std::move(E)); 30681ad6265SDimitry Andric return Error::success(); 30781ad6265SDimitry Andric } 30881ad6265SDimitry Andric 30981ad6265SDimitry Andric } // end namespace coff 31081ad6265SDimitry Andric } // end namespace objcopy 31181ad6265SDimitry Andric } // end namespace llvm 312