247 lines
8.5 KiB
C++
247 lines
8.5 KiB
C++
/* linker.h --
|
|
|
|
This file is part of the UPX executable compressor.
|
|
|
|
Copyright (C) 1996-2024 Markus Franz Xaver Johannes Oberhumer
|
|
Copyright (C) 1996-2024 Laszlo Molnar
|
|
All Rights Reserved.
|
|
|
|
UPX and the UCL library are free software; you can redistribute them
|
|
and/or modify them under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING.
|
|
If not, write to the Free Software Foundation, Inc.,
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
Markus F.X.J. Oberhumer Laszlo Molnar
|
|
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
/*************************************************************************
|
|
// ElfLinker
|
|
**************************************************************************/
|
|
|
|
class ElfLinker : private upx::noncopyable {
|
|
friend class Packer;
|
|
|
|
public:
|
|
const N_BELE_RTP::AbstractPolicy *const bele; // target endianness
|
|
protected:
|
|
struct Section;
|
|
struct Symbol;
|
|
struct Relocation;
|
|
|
|
byte *input = nullptr;
|
|
int inputlen = 0;
|
|
byte *output = nullptr;
|
|
int outputlen = 0;
|
|
unsigned output_capacity = 0;
|
|
|
|
Section *head = nullptr;
|
|
Section *tail = nullptr;
|
|
|
|
Section **sections = nullptr;
|
|
Symbol **symbols = nullptr;
|
|
Relocation **relocations = nullptr;
|
|
|
|
unsigned nsections = 0;
|
|
unsigned nsections_capacity = 0;
|
|
unsigned nsymbols = 0;
|
|
unsigned nsymbols_capacity = 0;
|
|
unsigned nrelocations = 0;
|
|
unsigned nrelocations_capacity = 0;
|
|
|
|
bool reloc_done = false;
|
|
|
|
protected:
|
|
void preprocessSections(char *start, char const *end);
|
|
void preprocessSymbols(char *start, char const *end);
|
|
void preprocessRelocations(char *start, char const *end);
|
|
Section *findSection(const char *name, bool fatal = true) const;
|
|
|
|
Symbol *addSymbol(const char *name, const char *section, upx_uint64_t offset);
|
|
Relocation *addRelocation(const char *section, unsigned off, const char *type,
|
|
const char *symbol, upx_uint64_t add);
|
|
|
|
public:
|
|
explicit ElfLinker(const N_BELE_RTP::AbstractPolicy *b = &N_BELE_RTP::le_policy) noexcept;
|
|
virtual ~ElfLinker() noexcept;
|
|
|
|
void init(const void *pdata, int plen, unsigned pxtra = 0);
|
|
// virtual void setLoaderAlignOffset(int phase);
|
|
int addLoader(const char *sname);
|
|
void addLoader(const char *s, va_list ap);
|
|
#if (ACC_CC_CLANG || ACC_CC_GNUC)
|
|
void addLoaderVA(const char *s, ...) __attribute__((__sentinel__));
|
|
#else
|
|
void addLoaderVA(const char *s, ...);
|
|
#endif
|
|
Section *addSection(const char *sname, const void *sdata, int slen, unsigned p2align);
|
|
int getSection(const char *sname, int *slen = nullptr) const;
|
|
int getSectionSize(const char *sname) const;
|
|
byte *getLoader(int *llen = nullptr) const;
|
|
void defineSymbol(const char *name, upx_uint64_t value);
|
|
Symbol *findSymbol(const char *name, bool fatal = true) const;
|
|
upx_uint64_t getSymbolOffset(const char *) const;
|
|
|
|
void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const;
|
|
void dumpSymbols(unsigned flags = 0, FILE *fp = nullptr) const;
|
|
|
|
void alignWithByte(unsigned len, byte b);
|
|
virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
|
|
virtual void alignData(unsigned len) { alignWithByte(len, 0); }
|
|
|
|
// provide overloads to pacify GitHub CodeQL
|
|
void defineSymbol(const char *name, int value) { defineSymbol(name, upx_uint64_t(value)); }
|
|
void defineSymbol(const char *name, unsigned value) { defineSymbol(name, upx_uint64_t(value)); }
|
|
void defineSymbol(const char *name, unsigned long value) {
|
|
defineSymbol(name, upx_uint64_t(value));
|
|
}
|
|
|
|
protected:
|
|
void relocate();
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type);
|
|
};
|
|
|
|
struct ElfLinker::Section : private upx::noncopyable {
|
|
char *name = nullptr;
|
|
void *input = nullptr;
|
|
byte *output = nullptr;
|
|
unsigned size = 0;
|
|
unsigned sort_id = 0; // for qsort()
|
|
upx_uint64_t offset = 0;
|
|
unsigned p2align = 0; // log2
|
|
Section *next = nullptr;
|
|
|
|
explicit Section(const char *n, const void *i, unsigned s, unsigned a = 0);
|
|
~Section() noexcept;
|
|
};
|
|
|
|
struct ElfLinker::Symbol : private upx::noncopyable {
|
|
char *name = nullptr;
|
|
Section *section = nullptr;
|
|
upx_uint64_t offset = 0;
|
|
|
|
explicit Symbol(const char *n, Section *s, upx_uint64_t o);
|
|
~Symbol() noexcept;
|
|
};
|
|
|
|
struct ElfLinker::Relocation : private upx::noncopyable {
|
|
const Section *section = nullptr;
|
|
unsigned offset = 0;
|
|
const char *type = nullptr;
|
|
const Symbol *value = nullptr;
|
|
upx_uint64_t add = 0; // used in .rela relocations
|
|
|
|
explicit Relocation(const Section *s, unsigned o, const char *t, const Symbol *v,
|
|
upx_uint64_t a);
|
|
~Relocation() noexcept {}
|
|
};
|
|
|
|
/*************************************************************************
|
|
// ElfLinker arch subclasses
|
|
**************************************************************************/
|
|
|
|
class ElfLinkerAMD64 /*not_final*/ : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void alignCode(unsigned len) override { alignWithByte(len, 0x90); }
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerArm64LE final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerArmBE final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
public:
|
|
explicit ElfLinkerArmBE() noexcept : super(&N_BELE_RTP::be_policy) {}
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerArmLE final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerM68k final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
public:
|
|
explicit ElfLinkerM68k() noexcept : super(&N_BELE_RTP::be_policy) {}
|
|
protected:
|
|
virtual void alignCode(unsigned len) override;
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerMipsBE final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
public:
|
|
explicit ElfLinkerMipsBE() noexcept : super(&N_BELE_RTP::be_policy) {}
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerMipsLE final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerPpc32 final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
public:
|
|
explicit ElfLinkerPpc32() noexcept : super(&N_BELE_RTP::be_policy) {}
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerPpc64 final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
public:
|
|
explicit ElfLinkerPpc64() noexcept : super(&N_BELE_RTP::be_policy) {}
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerPpc64le final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
class ElfLinkerX86 final : public ElfLinker {
|
|
typedef ElfLinker super;
|
|
protected:
|
|
virtual void alignCode(unsigned len) override { alignWithByte(len, 0x90); }
|
|
virtual void relocate1(const Relocation *, byte *location, upx_uint64_t value,
|
|
const char *type) override;
|
|
};
|
|
|
|
/* vim:set ts=4 sw=4 et: */
|