diff --git a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h index 59960b65307430..8427ca3abf65d5 100644 --- a/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h +++ b/llvm/include/llvm/ObjCopy/ELF/ELFConfig.h @@ -31,6 +31,7 @@ struct ELFConfig { bool KeepFileSymbols = false; bool LocalizeHidden = false; bool VerifyNoteSections = true; + std::optional MaxHugeSectionOffset; }; } // namespace objcopy diff --git a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 40598861d42731..22e376bf11d6ca 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -176,11 +176,12 @@ static std::unique_ptr createELFWriter(const CommonConfig &Config, } static std::unique_ptr createWriter(const CommonConfig &Config, + const ELFConfig &ELFConfig, Object &Obj, raw_ostream &Out, ElfType OutputElfType) { switch (Config.OutputFormat) { case FileFormat::Binary: - return std::make_unique(Obj, Out, Config); + return std::make_unique(Obj, Out, Config, ELFConfig); case FileFormat::IHex: return std::make_unique(Obj, Out, Config.OutputFilename); case FileFormat::SREC: @@ -926,10 +927,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 = - createWriter(Config, Obj, Out, OutputElfType); + createWriter(Config, ELFConfig, Obj, Out, OutputElfType); if (Error E = Writer->finalize()) return E; return Writer->write(); @@ -947,7 +948,7 @@ Error objcopy::elf::executeObjcopyOnIHex(const CommonConfig &Config, getOutputElfType(Config.OutputArch.value_or(MachineInfo())); if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType); } Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, @@ -965,7 +966,7 @@ Error objcopy::elf::executeObjcopyOnRawBinary(const CommonConfig &Config, getOutputElfType(Config.OutputArch.value_or(MachineInfo())); if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **Obj)) return E; - return writeOutput(Config, **Obj, Out, OutputElfType); + return writeOutput(Config, ELFConfig, **Obj, Out, OutputElfType); } Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, @@ -985,7 +986,7 @@ Error objcopy::elf::executeObjcopyOnBinary(const CommonConfig &Config, if (Error E = handleArgs(Config, ELFConfig, OutputElfType, **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 fd55f974115a24..7c55de1875b596 100644 --- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp +++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp @@ -2744,6 +2744,13 @@ Error BinaryWriter::finalize() { if (Sec.Type != SHT_NOBITS && Sec.Size > 0) { Sec.Offset = Sec.Addr - MinAddr; TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); + + if (MaxHugeSectionOffset) { + if (Sec.Offset > *MaxHugeSectionOffset) + return createStringError(errc::file_too_large, + "writing section " + Sec.Name + + " at huge file offset"); + } } Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize); diff --git a/llvm/lib/ObjCopy/ELF/ELFObject.h b/llvm/lib/ObjCopy/ELF/ELFObject.h index 6ccf85387131e4..5d80b7e57c7212 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; + std::optional MaxHugeSectionOffset; + 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), + MaxHugeSectionOffset(ELFConfig.MaxHugeSectionOffset) {} }; // A base class for writing ascii hex formats such as srec and ihex. diff --git a/llvm/test/tools/llvm-objcopy/ELF/disable-huge-section-offset.yaml b/llvm/test/tools/llvm-objcopy/ELF/disable-huge-section-offset.yaml new file mode 100644 index 00000000000000..40fd293156aebe --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/disable-huge-section-offset.yaml @@ -0,0 +1,27 @@ +# RUN: yaml2obj %s --docnum=1 -o %t +# RUN: not llvm-objcopy -O binary %t %t2 --set-max-huge-section-offset=2000000000 2>&1 | FileCheck %s + +# CHECK: writing section .high_addr at huge 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 26a888c628d9d3..fc25b3d6001f1f 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -1054,6 +1054,11 @@ objcopy::parseObjcopyOptions(ArrayRef RawArgsArr, Config.ExtractMainPartition = InputArgs.hasArg(OBJCOPY_extract_main_partition); ELFConfig.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden); + + if (auto *Arg = InputArgs.getLastArg(OBJCOPY_set_max_huge_section_offset)) { + ELFConfig.MaxHugeSectionOffset = std::stoull(Arg->getValue()); + } + 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 434b5ff92324eb..e493c70190f98e 100644 --- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td +++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td @@ -146,6 +146,12 @@ def extract_main_partition : Flag<["--"], "extract-main-partition">, HelpText<"Extract main partition from the input file">; +defm set_max_huge_section_offset + : Eq<"set-max-huge-section-offset", + "Emit an error if input section has a file offset greater than the " + "specified `offset`">, + MetaVarName<"offset">; + def localize_hidden : Flag<["--"], "localize-hidden">, HelpText<