COFFObjcopy.cpp 11 KB

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