[llvm] [llvm-objcopy][ELF] Disable huge section offset (PR #97036)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 28 03:38:06 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Djordje Todorovic (djtodoro)

<details>
<summary>Changes</summary>

Match GNU objcopy's behaviour.
This is controled by an option, that is set to OFF by defatult.

It addresses the problem described in [0].

https://github.com/llvm/llvm-project/issues/88878


---
Full diff: https://github.com/llvm/llvm-project/pull/97036.diff


7 Files Affected:

- (modified) llvm/include/llvm/ObjCopy/ELF/ELFConfig.h (+1) 
- (modified) llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp (+8-7) 
- (modified) llvm/lib/ObjCopy/ELF/ELFObject.cpp (+9) 
- (modified) llvm/lib/ObjCopy/ELF/ELFObject.h (+8-3) 
- (added) llvm/test/tools/llvm-objcopy/ELF/disable-huge-negative-offset.yaml (+27) 
- (modified) llvm/tools/llvm-objcopy/ObjcopyOptions.cpp (+2) 
- (modified) llvm/tools/llvm-objcopy/ObjcopyOpts.td (+4) 


``````````diff
diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
index eafed92516c7d..29e55fcddb23a 100644
--- a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
+++ b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h
@@ -30,6 +30,7 @@ struct ELFConfig {
   bool AllowBrokenLinks = false;
   bool KeepFileSymbols = false;
   bool LocalizeHidden = false;
+  bool DisableHugeSectionOffset = false;
 };
 
 } // namespace objcopy
diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
index f343d1447e055..b1231033bb509 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
@@ -176,11 +176,12 @@ static std::unique_ptr<Writer> createELFWriter(const CommonConfig &Config,
 }
 
 static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
+                                            const ELFConfig &ELFConfig,
                                             Object &Obj, raw_ostream &Out,
                                             ElfType OutputElfType) {
   switch (Config.OutputFormat) {
   case FileFormat::Binary:
-    return std::make_unique<BinaryWriter>(Obj, Out, Config);
+    return std::make_unique<BinaryWriter>(Obj, Out, Config, ELFConfig);
   case FileFormat::IHex:
     return std::make_unique<IHexWriter>(Obj, Out, Config.OutputFilename);
   case FileFormat::SREC:
@@ -794,10 +795,10 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
   return Error::success();
 }
 
-static Error writeOutput(const CommonConfig &Config, Object &Obj,
-                         raw_ostream &Out, ElfType OutputElfType) {
+static Error writeOutput(const CommonConfig &Config, const ELFConfig &ELFConfig,
+                         Object &Obj, raw_ostream &Out, ElfType OutputElfType) {
   std::unique_ptr<Writer> Writer =
-      createWriter(Config, Obj, Out, OutputElfType);
+      createWriter(Config, ELFConfig, Obj, Out, OutputElfType);
   if (Error E = Writer->finalize())
     return E;
   return Writer->write();
@@ -815,7 +816,7 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config,
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
   if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return E;
-  return writeOutput(Config, **Obj, Out, OutputElfType);
+  return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType);
 }
 
 Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
@@ -833,7 +834,7 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config,
       getOutputElfType(Config.OutputArch.value_or(MachineInfo()));
   if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return E;
-  return writeOutput(Config, **Obj, Out, OutputElfType);
+  return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType);
 }
 
 Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
@@ -853,7 +854,7 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config,
   if (Error E = handleArgs(Config, ELFConfig, **Obj))
     return createFileError(Config.InputFilename, std::move(E));
 
-  if (Error E = writeOutput(Config, **Obj, Out, OutputElfType))
+  if (Error E = writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType))
     return createFileError(Config.InputFilename, std::move(E));
 
   return Error::success();
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index 02591e6f987c2..9e090f4ff1cb7 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2706,6 +2706,15 @@ Error BinaryWriter::finalize() {
     if (Sec.Type != SHT_NOBITS && Sec.Size > 0) {
       Sec.Offset = Sec.Addr - MinAddr;
       TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size);
+
+      // More or less, this makes sense to do for 32-bit targets.
+      if (DisableHugeSectionOffset and not Obj.Is64Bits) {
+        int FilePosition = Sec.Offset;
+        if (FilePosition < 0)
+          return createStringError(errc::file_too_large,
+                                   "writing section " + Sec.Name +
+                                       " at huge (ie negative) file offset");
+      }
     }
 
   Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h
index 2b1895a30b41e..02abcfa7f10a0 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.h
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.h
@@ -15,6 +15,7 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/ObjCopy/CommonConfig.h"
+#include "llvm/ObjCopy/ELF/ELFConfig.h"
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/FileOutputBuffer.h"
@@ -366,12 +367,16 @@ class BinaryWriter : public Writer {
 
   uint64_t TotalSize = 0;
 
+  bool DisableHugeSectionOffset = false;
+
 public:
   ~BinaryWriter() {}
   Error finalize() override;
   Error write() override;
-  BinaryWriter(Object &Obj, raw_ostream &Out, const CommonConfig &Config)
-      : Writer(Obj, Out), GapFill(Config.GapFill), PadTo(Config.PadTo) {}
+  BinaryWriter(Object &Obj, raw_ostream &Out, const CommonConfig &Config,
+               const ELFConfig &ELFConfig)
+      : Writer(Obj, Out), GapFill(Config.GapFill), PadTo(Config.PadTo),
+        DisableHugeSectionOffset(ELFConfig.DisableHugeSectionOffset) {}
 };
 
 // A base class for writing ascii hex formats such as srec and ihex.
@@ -667,7 +672,7 @@ class CompressedSection : public SectionBase {
 
 public:
   CompressedSection(const SectionBase &Sec,
-    DebugCompressionType CompressionType, bool Is64Bits);
+                    DebugCompressionType CompressionType, bool Is64Bits);
   CompressedSection(ArrayRef<uint8_t> CompressedData, uint32_t ChType,
                     uint64_t DecompressedSize, uint64_t DecompressedAlign);
 
diff --git a/llvm/test/tools/llvm-objcopy/ELF/disable-huge-negative-offset.yaml b/llvm/test/tools/llvm-objcopy/ELF/disable-huge-negative-offset.yaml
new file mode 100644
index 0000000000000..5769211e2dd4f
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/disable-huge-negative-offset.yaml
@@ -0,0 +1,27 @@
+# RUN: yaml2obj %s --docnum=1 -o %t
+# RUN: not llvm-objcopy -O binary %t %t2 --disable-huge-section-offset 2>&1 | FileCheck %s
+
+# CHECK: writing section .high_addr at huge (ie negative) file offset
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_MIPS
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
+    Content:         "00112233445566778899AABBCCDDEEFF"
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x2000
+    Content:         "112233445566778899AABBCCDDEEFF00"
+  - Name:            .high_addr
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_WRITE ]
+    Address:         0x80001000
+    Content:         "2233445566778899AABBCCDDEEFF0011"
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 4ab3b7265f2f6..92728cb2ea865 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -942,6 +942,8 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
   Config.ExtractMainPartition =
       InputArgs.hasArg(OBJCOPY_extract_main_partition);
   ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
+  ELFConfig.DisableHugeSectionOffset =
+      InputArgs.hasArg(OBJCOPY_disable_huge_section_offsets);
   Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
   if (auto *Arg =
           InputArgs.getLastArg(OBJCOPY_discard_all, OBJCOPY_discard_locals)) {
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 4bc80eba05f8e..723f73ace7928 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -145,6 +145,10 @@ def localize_hidden
     : Flag<["--"], "localize-hidden">,
       HelpText<
           "Mark all symbols that have hidden or internal visibility as local">;
+def disable_huge_section_offsets
+    : Flag<["--"], "disable-huge-section-offset">,
+      HelpText<
+          "Emit an error if input section has a huge file offset">;
 defm localize_symbol
     : Eq<"localize-symbol", "Mark any defined non-common symbol named <symbol> as local">,
       MetaVarName<"symbol">;

``````````

</details>


https://github.com/llvm/llvm-project/pull/97036


More information about the llvm-commits mailing list