Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion llvm/cmake/modules/AddLLVM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,7 @@ if(NOT LLVM_TOOLCHAIN_TOOLS)
llvm-size
llvm-strings
llvm-strip
llvm-fromelf
llvm-profdata
llvm-symbolizer
# symlink version of some of above tools that are enabled by
Expand All @@ -1331,7 +1332,8 @@ if(NOT LLVM_TOOLCHAIN_TOOLS)
size
strings
strip
)
fromelf
)
# Build llvm-mt if libxml2 is enabled. Can be used by runtimes.
if (LLVM_ENABLE_LIBXML2)
list(APPEND LLVM_TOOLCHAIN_TOOLS llvm-mt)
Expand Down
5 changes: 4 additions & 1 deletion llvm/cmake/modules/LLVMExternalProjectUtils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function(llvm_ExternalProject_Add name source_dir)
endif()
else()
# TODO: These tools don't fully support Mach-O format yet.
list(APPEND ARG_TOOLCHAIN_TOOLS llvm-objcopy llvm-strip llvm-readelf)
list(APPEND ARG_TOOLCHAIN_TOOLS llvm-objcopy llvm-strip llvm-readelf llvm-fromelf)
endif()
endif()
endif()
Expand Down Expand Up @@ -225,6 +225,9 @@ function(llvm_ExternalProject_Add name source_dir)
if(llvm-strip IN_LIST TOOLCHAIN_TOOLS AND NOT ARG_STRIP_TOOL)
list(APPEND compiler_args -DCMAKE_STRIP=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-strip${CMAKE_EXECUTABLE_SUFFIX})
endif()
if(llvm-fromelf IN_LIST TOOLCHAIN_TOOLS AND NOT ARG_FROMELF_TOOL)
list(APPEND compiler_args -DCMAKE_STRIP=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-fromelf${CMAKE_EXECUTABLE_SUFFIX})
endif()
if(llvm-readelf IN_LIST TOOLCHAIN_TOOLS)
list(APPEND compiler_args -DCMAKE_READELF=${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-readelf${CMAKE_EXECUTABLE_SUFFIX})
endif()
Expand Down
9 changes: 3 additions & 6 deletions llvm/include/llvm/ObjCopy/CommonConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@
namespace llvm {
namespace objcopy {

enum class FileFormat {
Unspecified,
ELF,
Binary,
IHex,
};
enum class FileFormat { Unspecified, ELF, Binary, IHex, SegBin };

// This type keeps track of the machine info for various architectures. This
// lets us map architecture names to ELF types and the e_machine value of the
Expand Down Expand Up @@ -213,6 +208,8 @@ struct CommonConfig {
StringRef AddGnuDebugLink;
// Cached gnu_debuglink's target CRC
uint32_t GnuDebugLinkCRC32;
// Segment Index to be dumped
uint32_t SegmentIndex;
std::optional<StringRef> ExtractPartition;
StringRef SplitDWO;
StringRef SymbolsPrefix;
Expand Down
9 changes: 9 additions & 0 deletions llvm/include/llvm/Object/ELFObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ class ELFObjectFileBase : public ObjectFile {
// corresponding to the section with that index.
Expected<std::vector<BBAddrMap>>
readBBAddrMap(std::optional<unsigned> TextSectionIndex = std::nullopt) const;

virtual uint32_t getProgramHeaderCount() const = 0;
};

class ELFSectionRef : public SectionRef {
Expand Down Expand Up @@ -467,6 +469,8 @@ template <class ELFT> class ELFObjectFile : public ELFObjectFileBase {
bool isRelocatableObject() const override;

void createFakeSections() { EF.createFakeSections(); }

uint32_t getProgramHeaderCount() const override;
};

using ELF32LEObjectFile = ELFObjectFile<ELF32LE>;
Expand Down Expand Up @@ -553,6 +557,11 @@ uint64_t ELFObjectFile<ELFT>::getSectionOffset(DataRefImpl Sec) const {
return getSection(Sec)->sh_offset;
}

template <class ELFT>
uint32_t ELFObjectFile<ELFT>::getProgramHeaderCount() const {
return EF.getHeader().e_phnum;
}

template <class ELFT>
uint64_t ELFObjectFile<ELFT>::getSymbolValueImpl(DataRefImpl Symb) const {
Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ static std::unique_ptr<Writer> createWriter(const CommonConfig &Config,
return std::make_unique<BinaryWriter>(Obj, Out);
case FileFormat::IHex:
return std::make_unique<IHexWriter>(Obj, Out);
case FileFormat::SegBin:
return std::make_unique<SegBinWriter>(Obj, Out, Config.SegmentIndex);
default:
return createELFWriter(Config, Obj, Out, OutputElfType);
}
Expand Down
26 changes: 26 additions & 0 deletions llvm/lib/ObjCopy/ELF/ELFObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,13 @@ Error SectionWriter::visit(const Section &Sec) {
return Error::success();
}

Error BinarySegmentWriter::visit(const Segment &Seg) {
if (Seg.Type == PT_LOAD)
llvm::copy(Seg.Contents, Out.getBufferStart());

return Error::success();
}

static bool addressOverflows32bit(uint64_t Addr) {
// Sign extended 32 bit addresses (e.g 0xFFFFFFFF80000000) are ok
return Addr > UINT32_MAX && Addr + 0x80000000 > UINT32_MAX;
Expand Down Expand Up @@ -2679,6 +2686,25 @@ Error BinaryWriter::finalize() {
return Error::success();
}

Error SegBinWriter::write() {
const Segment &Seg = Obj.getSegmentForIndex(SegmentIndex);
if (Error Err = Seg.accept(*SegmentWriter))
return Err;
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
return Error::success();
}

Error SegBinWriter::finalize() {
const Segment &Seg = Obj.getSegmentForIndex(SegmentIndex);
Buf = WritableMemoryBuffer::getNewMemBuffer(Seg.FileSize);
if (!Buf)
return createStringError(errc::not_enough_memory,
"failed to allocate memory buffer of " +
Twine::utohexstr(Seg.FileSize) + " bytes");
SegmentWriter = std::make_unique<BinarySegmentWriter>(*Buf);
return Error::success();
}

bool IHexWriter::SectionCompare::operator()(const SectionBase *Lhs,
const SectionBase *Rhs) const {
return (sectionPhysicalAddr(Lhs) & 0xFFFFFFFFU) <
Expand Down
58 changes: 57 additions & 1 deletion llvm/lib/ObjCopy/ELF/ELFObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ class SectionVisitor {
virtual Error visit(const DecompressedSection &Sec) = 0;
};

class SegmentVisitor {
public:
virtual ~SegmentVisitor() = default;

virtual Error visit(const Segment &Seg) = 0;
};

class MutableSectionVisitor {
public:
virtual ~MutableSectionVisitor() = default;
Expand Down Expand Up @@ -126,6 +133,18 @@ class SectionWriter : public SectionVisitor {
explicit SectionWriter(WritableMemoryBuffer &Buf) : Out(Buf) {}
};

class SegmentWriter : public SegmentVisitor {
protected:
WritableMemoryBuffer &Out;

public:
virtual ~SegmentWriter() = default;

Error visit(const Segment &Seg) override = 0;

explicit SegmentWriter(WritableMemoryBuffer &Buf) : Out(Buf) {}
};

template <class ELFT> class ELFSectionWriter : public SectionWriter {
private:
using Elf_Word = typename ELFT::Word;
Expand Down Expand Up @@ -191,6 +210,16 @@ class BinarySectionWriter : public SectionWriter {
: SectionWriter(Buf) {}
};

class BinarySegmentWriter : public SegmentWriter {
public:
virtual ~BinarySegmentWriter() {}

Error visit(const Segment &Seg) override;

explicit BinarySegmentWriter(WritableMemoryBuffer &Buf)
: SegmentWriter(Buf) {}
};

using IHexLineData = SmallVector<char, 64>;

struct IHexRecord {
Expand Down Expand Up @@ -387,6 +416,19 @@ class IHexWriter : public Writer {
IHexWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}
};

class SegBinWriter : public Writer {
private:
std::unique_ptr<BinarySegmentWriter> SegmentWriter;
uint32_t SegmentIndex = 0;

public:
~SegBinWriter() {}
Error finalize() override;
Error write() override;
SegBinWriter(Object &Obj, raw_ostream &Out, uint32_t SegmentIndex)
: Writer(Obj, Out), SegmentIndex(SegmentIndex) {}
};

class SectionBase {
public:
std::string Name;
Expand Down Expand Up @@ -476,7 +518,7 @@ class Segment {

void removeSection(const SectionBase *Sec) { Sections.erase(Sec); }
void addSection(const SectionBase *Sec) { Sections.insert(Sec); }

Error accept(SegmentVisitor &Visitor) const { return Visitor.visit(*this); }
ArrayRef<uint8_t> getContents() const { return Contents; }
};

Expand Down Expand Up @@ -1036,6 +1078,9 @@ class Object {
static bool sectionIsAlloc(const SectionBase &Sec) {
return Sec.Flags & ELF::SHF_ALLOC;
};
static bool segmentIsLoadable(const Segment &Seg) {
return Seg.Type & ELF::PT_LOAD;
};

public:
template <class T>
Expand Down Expand Up @@ -1087,6 +1132,17 @@ class Object {
}
SectionTableRef removedSections() { return SectionTableRef(RemovedSections); }

iterator_range<
filter_iterator<pointee_iterator<std::vector<SegPtr>::const_iterator>,
decltype(&segmentIsLoadable)>>
loadableSegments() const {
return make_filter_range(make_pointee_range(Segments), segmentIsLoadable);
}

const Segment &getSegmentForIndex(uint32_t Index) const {
return *(Segments[Index]);
}

ConstRange<Segment> segments() const { return make_pointee_range(Segments); }

Error removeSections(bool AllowBrokenLinks,
Expand Down
1 change: 1 addition & 0 deletions llvm/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ set(LLVM_TEST_DEPENDS
llvm-stress
llvm-strings
llvm-strip
llvm-fromelf
llvm-symbolizer
llvm-tblgen
llvm-readtapi
Expand Down
2 changes: 2 additions & 0 deletions llvm/test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def get_asan_rtlib():
ToolSubst("%llvm-strip", FindTool("llvm-strip")),
ToolSubst("%llvm-install-name-tool", FindTool("llvm-install-name-tool")),
ToolSubst("%llvm-bitcode-strip", FindTool("llvm-bitcode-strip")),
ToolSubst("%llvm-fromelf", FindTool("llvm-fromelf")),
ToolSubst("%split-file", FindTool("split-file")),
]

Expand All @@ -180,6 +181,7 @@ def get_asan_rtlib():
"llvm-addr2line",
"llvm-bcanalyzer",
"llvm-bitcode-strip",
"llvm-fromelf",
"llvm-config",
"llvm-cov",
"llvm-cxxdump",
Expand Down
43 changes: 43 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/basic-segment-binary-copy.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy -I elf -O sbin %t %t2
# RUN: llvm-fromelf -O sbin %t %t3

!ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .foo
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000001000
Size: 8
- Name: .bar
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000001000
Size: 8
- Name: .main
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
AddressAlign: 0x0000000000001000
Size: 64
ProgramHeaders:
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
FirstSec: .foo
LastSec: .foo
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
VAddr: 0x2000000
PAddr: 0x2000000
FirstSec: .bar
LastSec: .bar
- Type: PT_LOAD
Flags: [ PF_X, PF_R ]
FirstSec: .main
LastSec: .main
VAddr: 0x2000008
PAddr: 0x2000008
12 changes: 12 additions & 0 deletions llvm/test/tools/llvm-objcopy/tool-help-message.test
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# RUN: not llvm-objcopy -abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG-SHORT %s
# RUN: not llvm-objcopy --abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG-LONG %s
# RUN: not llvm-objcopy --strip-debug 2>&1 | FileCheck %s --check-prefix=NO-INPUT-FILES
# RUN: not llvm-objcopy --input-target binary --output-target sbin f1 2>&1 | FileCheck %s --check-prefix=SEGBIN

# RUN: llvm-strip -h | FileCheck --check-prefix=STRIP-USAGE %s --match-full-lines
# RUN: llvm-strip --help | FileCheck --check-prefix=STRIP-USAGE %s --match-full-lines
Expand All @@ -29,6 +30,13 @@
# RUN: not llvm-bitcode-strip --abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG-LONG %s
# RUN: not llvm-bitcode-strip f1 f2 2>&1 | FileCheck %s --check-prefix=MULTIPLE-INPUT-FILES

# RUN: llvm-fromelf -h | FileCheck --check-prefix=FROMELF-USAGE %s --match-full-lines
# RUN: llvm-fromelf --help | FileCheck --check-prefix=FROMELF-USAGE %s --match-full-lines
# RUN: not llvm-fromelf 2>&1 | FileCheck --check-prefix=FROMELF-USAGE %s --match-full-lines
# RUN: not llvm-fromelf -- 2>&1 | FileCheck --check-prefix=FROMELF-USAGE %s --match-full-lines
# RUN: not llvm-fromelf -abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG-LONG %s
# RUN: not llvm-fromelf --abcabc 2>&1 | FileCheck --check-prefix=UNKNOWN-ARG-LONG %s

# OBJCOPY-USAGE: USAGE: llvm-objcopy [options] input [output]
# OBJCOPY-USAGE: Pass @FILE as argument to read options from FILE.

Expand All @@ -41,7 +49,11 @@
# BITCODE-STRIP-USAGE: USAGE: llvm-bitcode-strip [options] input
# BITCODE-STRIP-USAGE: Pass @FILE as argument to read options from FILE.

# FROMELF-USAGE: USAGE: llvm-fromelf [options] input [output]
# FROMELF-USAGE: Pass @FILE as argument to read options from FILE.

# UNKNOWN-ARG-SHORT: unknown argument '-a'
# UNKNOWN-ARG-LONG: unknown argument '{{-+}}abcabc'
# NO-INPUT-FILES: no input file specified
# MULTIPLE-INPUT-FILES: expects a single input file
# SEGBIN: --output-target sbin can be used with only --input-target elf
10 changes: 10 additions & 0 deletions llvm/test/tools/llvm-objcopy/tool-name.test
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@
# RUN: %t/bitcode_strip.exe --help | FileCheck --check-prefix=BITCODE-STRIP %s

# BITCODE-STRIP: OVERVIEW: llvm-bitcode-strip tool

## This driver emulates fromelf from ARM.
# RUN: ln -s llvm-fromelf %t/llvm-fromelf-10
# RUN: ln -s llvm-fromelf %t/fromelf.exe

# RUN: llvm-fromelf --help | FileCheck --check-prefix=FROM-ELF %s
# RUN: %t/llvm-fromelf-10 --help | FileCheck --check-prefix=FROM-ELF %s
# RUN: %t/fromelf.exe --help | FileCheck --check-prefix=FROM-ELF %s

# FROM-ELF: OVERVIEW: llvm-fromelf tool
3 changes: 3 additions & 0 deletions llvm/test/tools/llvm-objcopy/tool-version.test
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
# RUN: llvm-bitcode-strip --version | FileCheck %s
# RUN: llvm-bitcode-strip -V | FileCheck %s

# RUN: llvm-fromelf --version | FileCheck %s
# RUN: llvm-fromelf -V | FileCheck %s

# OBJCOPY-DAG: {{ version }}
# OBJCOPY-DAG: GNU objcopy

Expand Down
Loading