[llvm-objcopy][MachO] Support LC_LINKER_OPTIMIZATION_HINT load command
authorFangrui Song <i@maskray.me>
Wed, 30 Jun 2021 01:47:55 +0000 (18:47 -0700)
committerFangrui Song <i@maskray.me>
Wed, 30 Jun 2021 01:47:55 +0000 (18:47 -0700)
The load command is currently specific to arm64 and holds information
for instruction rewriting, e.g.  converting a GOT load to an ADR to
compute a local address.
(On ELF the information is usually conveyed by relocations, e.g.
R_X86_64_REX_GOTPCRELX, R_PPC64_TOC16_HA)

Reviewed By: alexander-shaposhnikov

Differential Revision: https://reviews.llvm.org/D104968

llvm/test/tools/llvm-objcopy/MachO/lc-linker-optimization-hint.s [new file with mode: 0644]
llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp
llvm/tools/llvm-objcopy/MachO/MachOReader.cpp
llvm/tools/llvm-objcopy/MachO/MachOReader.h
llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp
llvm/tools/llvm-objcopy/MachO/MachOWriter.h
llvm/tools/llvm-objcopy/MachO/Object.cpp
llvm/tools/llvm-objcopy/MachO/Object.h

diff --git a/llvm/test/tools/llvm-objcopy/MachO/lc-linker-optimization-hint.s b/llvm/test/tools/llvm-objcopy/MachO/lc-linker-optimization-hint.s
new file mode 100644 (file)
index 0000000..2c2ec6f
--- /dev/null
@@ -0,0 +1,25 @@
+# REQUIRES: aarch64-registered-target
+## Test that we can copy LC_LINKER_OPTIMIZATION_HINT.
+
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %s -o %t.o
+# RUN: llvm-objdump --macho --link-opt-hints - < %t.o > %tloh.txt
+# RUN: FileCheck --input-file=%tloh.txt %s
+
+# CHECK:      Linker optimiztion hints (8 total bytes)
+# CHECK-NEXT:   identifier 7 AdrpAdd
+
+# RUN: llvm-objcopy %t.o %t.copy.o
+# RUN: llvm-objdump --macho --link-opt-hints - < %t.copy.o | diff %tloh.txt -
+
+.text
+.align 2
+_test:
+L1:
+  adrp  x0, _foo@PAGE
+L2:
+  add   x0, x0, _foo@PAGEOFF
+.loh AdrpAdd L1, L2
+
+.data
+_foo:
+  .long 0
index 8dc4259..6ed2180 100644 (file)
@@ -251,7 +251,10 @@ Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
   uint64_t StartOfFunctionStarts = StartOfExportTrie + O.Exports.Trie.size();
   uint64_t StartOfDataInCode =
       StartOfFunctionStarts + O.FunctionStarts.Data.size();
-  uint64_t StartOfSymbols = StartOfDataInCode + O.DataInCode.Data.size();
+  uint64_t StartOfLinkerOptimizationHint =
+      StartOfDataInCode + O.DataInCode.Data.size();
+  uint64_t StartOfSymbols =
+      StartOfLinkerOptimizationHint + O.LinkerOptimizationHint.Data.size();
   uint64_t StartOfIndirectSymbols =
       StartOfSymbols + NListSize * O.SymTable.Symbols.size();
   uint64_t StartOfSymbolStrings =
@@ -320,6 +323,11 @@ Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
       MLC.linkedit_data_command_data.dataoff = StartOfDataInCode;
       MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size();
       break;
+    case MachO::LC_LINKER_OPTIMIZATION_HINT:
+      MLC.linkedit_data_command_data.dataoff = StartOfLinkerOptimizationHint;
+      MLC.linkedit_data_command_data.datasize =
+          O.LinkerOptimizationHint.Data.size();
+      break;
     case MachO::LC_FUNCTION_STARTS:
       MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts;
       MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size();
@@ -355,7 +363,6 @@ Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
     // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 need to be adjusted.
     case MachO::LC_ENCRYPTION_INFO:
     case MachO::LC_ENCRYPTION_INFO_64:
-    case MachO::LC_LINKER_OPTIMIZATION_HINT:
     case MachO::LC_LOAD_DYLINKER:
     case MachO::LC_MAIN:
     case MachO::LC_RPATH:
index da47e4b..7d1c29b 100644 (file)
@@ -151,6 +151,9 @@ Error MachOReader::readLoadCommands(Object &O) const {
     case MachO::LC_DATA_IN_CODE:
       O.DataInCodeCommandIndex = O.LoadCommands.size();
       break;
+    case MachO::LC_LINKER_OPTIMIZATION_HINT:
+      O.LinkerOptimizationHintCommandIndex = O.LoadCommands.size();
+      break;
     case MachO::LC_FUNCTION_STARTS:
       O.FunctionStartsCommandIndex = O.LoadCommands.size();
       break;
@@ -276,6 +279,11 @@ void MachOReader::readDataInCodeData(Object &O) const {
   return readLinkData(O, O.DataInCodeCommandIndex, O.DataInCode);
 }
 
+void MachOReader::readLinkerOptimizationHint(Object &O) const {
+  return readLinkData(O, O.LinkerOptimizationHintCommandIndex,
+                      O.LinkerOptimizationHint);
+}
+
 void MachOReader::readFunctionStartsData(Object &O) const {
   return readLinkData(O, O.FunctionStartsCommandIndex, O.FunctionStarts);
 }
@@ -330,6 +338,7 @@ Expected<std::unique_ptr<Object>> MachOReader::create() const {
   readExportInfo(*Obj);
   readCodeSignature(*Obj);
   readDataInCodeData(*Obj);
+  readLinkerOptimizationHint(*Obj);
   readFunctionStartsData(*Obj);
   readIndirectSymbolTable(*Obj);
   readSwiftVersion(*Obj);
index b446e02..ca3a021 100644 (file)
@@ -39,6 +39,7 @@ class MachOReader : public Reader {
   void readLinkData(Object &O, Optional<size_t> LCIndex, LinkData &LD) const;
   void readCodeSignature(Object &O) const;
   void readDataInCodeData(Object &O) const;
+  void readLinkerOptimizationHint(Object &O) const;
   void readFunctionStartsData(Object &O) const;
   void readIndirectSymbolTable(Object &O) const;
   void readSwiftVersion(Object &O) const;
index 24a9d28..295098e 100644 (file)
@@ -107,6 +107,16 @@ size_t MachOWriter::totalSize() const {
                      LinkEditDataCommand.datasize);
   }
 
+  if (O.LinkerOptimizationHintCommandIndex) {
+    const MachO::linkedit_data_command &LinkEditDataCommand =
+        O.LoadCommands[*O.LinkerOptimizationHintCommandIndex]
+            .MachOLoadCommand.linkedit_data_command_data;
+
+    if (LinkEditDataCommand.dataoff)
+      Ends.push_back(LinkEditDataCommand.dataoff +
+                     LinkEditDataCommand.datasize);
+  }
+
   if (O.FunctionStartsCommandIndex) {
     const MachO::linkedit_data_command &LinkEditDataCommand =
         O.LoadCommands[*O.FunctionStartsCommandIndex]
@@ -421,6 +431,11 @@ void MachOWriter::writeDataInCodeData() {
   return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode);
 }
 
+void MachOWriter::writeLinkerOptimizationHint() {
+  return writeLinkData(O.LinkerOptimizationHintCommandIndex,
+                       O.LinkerOptimizationHint);
+}
+
 void MachOWriter::writeFunctionStartsData() {
   return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts);
 }
@@ -490,6 +505,16 @@ void MachOWriter::writeTail() {
                          &MachOWriter::writeDataInCodeData);
   }
 
+  if (O.LinkerOptimizationHintCommandIndex) {
+    const MachO::linkedit_data_command &LinkEditDataCommand =
+        O.LoadCommands[*O.LinkerOptimizationHintCommandIndex]
+            .MachOLoadCommand.linkedit_data_command_data;
+
+    if (LinkEditDataCommand.dataoff)
+      Queue.emplace_back(LinkEditDataCommand.dataoff,
+                         &MachOWriter::writeLinkerOptimizationHint);
+  }
+
   if (O.FunctionStartsCommandIndex) {
     const MachO::linkedit_data_command &LinkEditDataCommand =
         O.LoadCommands[*O.FunctionStartsCommandIndex]
index 24d3671..c8c06d6 100644 (file)
@@ -48,6 +48,7 @@ class MachOWriter {
   void writeLinkData(Optional<size_t> LCIndex, const LinkData &LD);
   void writeCodeSignatureData();
   void writeDataInCodeData();
+  void writeLinkerOptimizationHint();
   void writeFunctionStartsData();
   void writeTail();
 
index c82dae6..b4f98fa 100644 (file)
@@ -46,6 +46,9 @@ void Object::updateLoadCommandIndexes() {
     case MachO::LC_DATA_IN_CODE:
       DataInCodeCommandIndex = Index;
       break;
+    case MachO::LC_LINKER_OPTIMIZATION_HINT:
+      LinkerOptimizationHintCommandIndex = Index;
+      break;
     case MachO::LC_FUNCTION_STARTS:
       FunctionStartsCommandIndex = Index;
       break;
index 978bd80..207502e 100644 (file)
@@ -313,6 +313,7 @@ struct Object {
   ExportInfo Exports;
   IndirectSymbolTable IndirectSymTable;
   LinkData DataInCode;
+  LinkData LinkerOptimizationHint;
   LinkData FunctionStarts;
   LinkData CodeSignature;
 
@@ -328,6 +329,8 @@ struct Object {
   Optional<size_t> DySymTabCommandIndex;
   /// The index LC_DATA_IN_CODE load comamnd if present.
   Optional<size_t> DataInCodeCommandIndex;
+  /// The index of LC_LINKER_OPTIMIZATIN_HINT load comamnd if present.
+  Optional<size_t> LinkerOptimizationHintCommandIndex;
   /// The index LC_FUNCTION_STARTS load comamnd if present.
   Optional<size_t> FunctionStartsCommandIndex;