1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Major cleanup of ElfLinker.

This commit is contained in:
Markus F.X.J. Oberhumer 2006-11-12 10:57:18 +01:00
parent 6e763b0b42
commit a74e239e28
4 changed files with 217 additions and 155 deletions

View File

@ -29,7 +29,7 @@
#include "conf.h"
#include "linker.h"
static int hex(unsigned char c)
static unsigned hex(unsigned char c)
{
return (c & 0xf) + (c > '9' ? 9 : 0);
}
@ -45,17 +45,20 @@ static bool update_capacity(unsigned size, unsigned *capacity)
return true;
}
/*************************************************************************
//
// Section
**************************************************************************/
ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a) :
name(strdup(n)), output(NULL), size(s), offset(0), align(a), next(NULL)
name(NULL), output(NULL), size(s), offset(0), p2align(a), next(NULL)
{
assert(name);
name = strdup(n);
assert(name != NULL);
input = malloc(s + 1);
assert(input);
assert(input != NULL);
memcpy(input, i, s);
((char *)input)[s] = 0;
}
ElfLinker::Section::~Section()
@ -64,10 +67,17 @@ ElfLinker::Section::~Section()
free(input);
}
/*************************************************************************
// Symbol
**************************************************************************/
ElfLinker::Symbol::Symbol(const char *n, Section *s, unsigned o) :
name(strdup(n)), section(s), offset(o)
name(NULL), section(s), offset(o)
{
assert(name);
name = strdup(n);
assert(name != NULL);
assert(section != NULL);
}
ElfLinker::Symbol::~Symbol()
@ -75,12 +85,77 @@ ElfLinker::Symbol::~Symbol()
free(name);
}
/*************************************************************************
// Relocation
**************************************************************************/
ElfLinker::Relocation::Relocation(const Section *s, unsigned o, const char *t,
const Symbol *v, unsigned a) :
section(s), offset(o), type(t), value(v), add(a)
{}
{
assert(section != NULL);
}
/*************************************************************************
// ElfLinker
**************************************************************************/
ElfLinker::ElfLinker() :
input(NULL), output(NULL), head(NULL), tail(NULL),
sections(NULL), symbols(NULL), relocations(NULL),
nsections(0), nsections_capacity(0),
nsymbols(0), nsymbols_capacity(0),
nrelocations(0), nrelocations_capacity(0),
reloc_done(false)
{
}
ElfLinker::~ElfLinker()
{
delete [] input;
delete [] output;
unsigned ic;
for (ic = 0; ic < nsections; ic++)
delete sections[ic];
free(sections);
for (ic = 0; ic < nsymbols; ic++)
delete symbols[ic];
free(symbols);
for (ic = 0; ic < nrelocations; ic++)
delete relocations[ic];
free(relocations);
}
void ElfLinker::init(const void *pdata, int plen)
{
upx_byte *i = new upx_byte[plen + 1];
memcpy(i, pdata, plen);
input = i;
inputlen = plen;
input[plen] = 0;
output = new upx_byte[plen];
outputlen = 0;
int pos = find(input, plen, "Sections:", 9);
assert(pos != -1);
char *psections = (char *) input + pos;
char *psymbols = strstr(psections, "SYMBOL TABLE:");
assert(psymbols != NULL);
char *prelocs = strstr(psymbols, "RELOCATION RECORDS FOR");
assert(prelocs != NULL);
preprocessSections(psections, psymbols);
preprocessSymbols(psymbols, prelocs);
preprocessRelocations(prelocs, (char*) input + inputlen);
addLoader("*UND*");
}
void ElfLinker::preprocessSections(char *start, const char *end)
{
nsections = 0;
@ -114,22 +189,28 @@ void ElfLinker::preprocessSymbols(char *start, const char *end)
{
char section[1024];
char symbol[1024];
unsigned offset;
unsigned value, offset;
char *nextl = strchr(start, '\n');
assert(nextl != NULL);
if (sscanf(start, "%x%*8c %1024s %*x %1023s",
if (sscanf(start, "%x g *ABS* %x %1023s",
&value, &offset, symbol) == 3)
{
char *s = strstr(start, symbol);
s[strlen(symbol)] = 0;
addSymbol(s, "*ABS*", value);
assert(offset == 0);
}
else if (sscanf(start, "%x%*8c %1023s %*x %1023s",
&offset, section, symbol) == 3)
{
char *s = strstr(start, symbol);
s[strlen(symbol)] = 0;
if (strcmp(section, "*UND*") == 0)
offset = 0xdeaddead;
assert(strcmp(section, "*ABS*") != 0);
addSymbol(s, section, offset);
//printf("symbol %s preprocessed o=%x\n", s, offset);
}
start = nextl + 1;
@ -185,38 +266,54 @@ void ElfLinker::preprocessRelocations(char *start, const char *end)
}
}
ElfLinker::Section *ElfLinker::findSection(const char *name) const
ElfLinker::Section *ElfLinker::findSection(const char *name, bool fatal) const
{
for (unsigned ic = 0; ic < nsections; ic++)
if (strcmp(sections[ic]->name, name) == 0)
return sections[ic];
printf("unknown section %s\n", name);
abort();
if (fatal)
{
printf("unknown section %s\n", name);
abort();
}
return NULL;
}
ElfLinker::Symbol *ElfLinker::findSymbol(const char *name) /*const*/
ElfLinker::Symbol *ElfLinker::findSymbol(const char *name, bool fatal) const
{
for (unsigned ic = 0; ic < nsymbols; ic++)
if (strcmp(symbols[ic]->name, name) == 0)
return symbols[ic];
// FIXME: this should be a const method !
if ('*' == name[0]) // *ABS*
return addSymbol(name, name, 0);
printf("unknown symbol %s\n", name);
abort();
if (fatal)
{
printf("unknown symbol %s\n", name);
abort();
}
return NULL;
}
ElfLinker::Symbol *ElfLinker::addSymbol(const char *name, const char *section,
unsigned offset)
ElfLinker::Section *ElfLinker::addSection(const char *sname, const void *sdata, int slen, unsigned p2align)
{
//printf("addSection: %s len=%d align=%d\n", sname, slen, p2align);
if (update_capacity(nsections, &nsections_capacity))
sections = static_cast<Section **>(realloc(sections, nsections_capacity * sizeof(Section *)));
assert(sections);
assert(sname); assert(sname[0]); assert(sname[strlen(sname)-1] != ':');
assert(findSection(sname, false) == NULL);
Section *sec = new Section(sname, sdata, slen, p2align);
sections[nsections++] = sec;
return sec;
}
ElfLinker::Symbol *ElfLinker::addSymbol(const char *name, const char *section,
unsigned offset)
{
//printf("addSymbol: %s %s 0x%x\n", name, section, offset);
if (update_capacity(nsymbols, &nsymbols_capacity))
symbols = static_cast<Symbol **>(realloc(symbols, nsymbols_capacity * sizeof(Symbol *)));
assert(symbols != NULL);
assert(name); assert(name[0]); assert(name[strlen(name)-1] != ':');
assert(findSymbol(name, false) == NULL);
Symbol *sym = new Symbol(name, findSection(section), offset);
symbols[nsymbols++] = sym;
return sym;
@ -235,59 +332,6 @@ ElfLinker::Relocation *ElfLinker::addRelocation(const char *section, unsigned of
return rel;
}
ElfLinker::ElfLinker() :
frozen(false), input(NULL), output(NULL), head(NULL), tail(NULL),
sections(NULL), symbols(NULL), relocations(NULL),
nsections(0), nsections_capacity(0),
nsymbols(0), nsymbols_capacity(0),
nrelocations(0), nrelocations_capacity(0)
{
}
ElfLinker::~ElfLinker()
{
delete [] input;
delete [] output;
unsigned ic;
for (ic = 0; ic < nsections; ic++)
delete sections[ic];
free(sections);
for (ic = 0; ic < nsymbols; ic++)
delete symbols[ic];
free(symbols);
for (ic = 0; ic < nrelocations; ic++)
delete relocations[ic];
free(relocations);
}
void ElfLinker::init(const void *pdata, int plen)
{
upx_byte *i = new upx_byte[plen + 1];
memcpy(i, pdata, plen);
input = i;
inputlen = plen;
output = new upx_byte[plen];
outputlen = 0;
int pos = find(input, plen, "Sections:", 9);
assert(pos != -1);
char *psections = pos + (char *) input;
char *psymbols = strstr(psections, "SYMBOL TABLE:");
assert(psymbols != NULL);
char *prelocs = strstr(psymbols, "RELOCATION RECORDS FOR");
assert(prelocs != NULL);
input[plen] = 0;
preprocessSections(psections, psymbols);
preprocessSymbols(psymbols, prelocs);
preprocessRelocations(prelocs, (char*) input + inputlen);
addLoader("*UND*");
}
void ElfLinker::setLoaderAlignOffset(int phase)
{
//assert(phase & 0);
@ -296,7 +340,6 @@ void ElfLinker::setLoaderAlignOffset(int phase)
int ElfLinker::addLoader(const char *sname)
{
assert(!frozen);
if (sname[0] == 0)
return outputlen;
@ -311,27 +354,28 @@ int ElfLinker::addLoader(const char *sname)
break;
}
if (*sect == '+') // alignment
if (sect[0] == '+') // alignment
{
assert(tail);
if (unsigned l = (hex(sect[2]) - tail->offset - tail->size)
% hex(sect[1]))
unsigned l = (hex(sect[2]) - tail->offset - tail->size) % hex(sect[1]);
if (l)
{
alignCode(l);
if (sect[3] == 'D')
alignData(l);
else
alignCode(l);
tail->size += l;
outputlen += l;
}
}
else
{
Section *section = findSection(sect);
if (section->align) {
unsigned const v = ~0u << section->align;
if (section->p2align) {
assert(tail);
unsigned const v = ~0u << section->p2align;
if (unsigned const l = ~v & -(tail->offset + tail->size)) {
alignCode(l);
tail->size += l;
outputlen += l;
}
}
memcpy(output + outputlen, section->input, section->size);
@ -354,38 +398,22 @@ int ElfLinker::addLoader(const char *sname)
return outputlen;
}
void ElfLinker::addSection(const char *sname, const void *sdata, int slen, int align)
int ElfLinker::getSection(const char *sname, int *slen) const
{
assert(!frozen);
if (update_capacity(nsections, &nsections_capacity))
sections = static_cast<Section **>(realloc(sections, nsections_capacity * sizeof(Section *)));
assert(sections);
Section *sec = new Section(sname, sdata, slen, align);
sections[nsections++] = sec;
//return sec;
}
void ElfLinker::freeze()
{
if (frozen)
return;
frozen = true;
}
int ElfLinker::getSection(const char *sname, int *slen)
{
assert(frozen);
Section *section = findSection(sname);
const Section *section = findSection(sname);
if (slen)
*slen = section->size;
return section->output - output;
}
upx_byte *ElfLinker::getLoader(int *llen)
int ElfLinker::getSectionSize(const char *sname) const
{
assert(frozen);
const Section *section = findSection(sname);
return section->size;
}
upx_byte *ElfLinker::getLoader(int *llen) const
{
if (llen)
*llen = outputlen;
return output;
@ -393,31 +421,38 @@ upx_byte *ElfLinker::getLoader(int *llen)
void ElfLinker::relocate()
{
assert(frozen);
assert(!reloc_done);
reloc_done = true;
for (unsigned ic = 0; ic < nrelocations; ic++)
{
Relocation *rel = relocations[ic];
const Relocation *rel = relocations[ic];
unsigned value;
if (rel->section->output == NULL)
continue;
if (rel->value->section->output == NULL)
if (strcmp(rel->value->section->name, "*ABS*") == 0)
{
value = rel->value->offset;
}
else if (strcmp(rel->value->section->name, "*UND*") == 0 &&
rel->value->offset == 0xdeaddead)
{
printf("undefined symbol '%s' referenced\n", rel->value->name);
abort();
}
else if (rel->value->section->output == NULL)
{
printf("can not apply reloc '%s:%x' without section '%s'\n",
rel->section->name, rel->offset,
rel->value->section->name);
abort();
}
if (strcmp(rel->value->section->name, "*UND*") == 0 &&
rel->value->offset == 0xdeaddead)
else
{
printf("undefined symbol '%s' referenced\n", rel->value->name);
abort();
value = rel->value->section->offset +
rel->value->offset + rel->add;
}
unsigned value = rel->value->section->offset +
rel->value->offset + rel->add;
upx_byte *location = rel->section->output + rel->offset;
relocate1(rel, location, value, rel->type);
}
}
@ -425,7 +460,12 @@ void ElfLinker::relocate()
void ElfLinker::defineSymbol(const char *name, unsigned value)
{
Symbol *symbol = findSymbol(name);
if (strcmp(symbol->section->name, "*UND*") == 0) // for undefined symbols
if (strcmp(symbol->section->name, "*ABS*") == 0)
{
printf("defineSymbol: symbol '%s' is *ABS*\n", name);
abort();
}
else if (strcmp(symbol->section->name, "*UND*") == 0) // for undefined symbols
symbol->offset = value;
else if (strcmp(symbol->section->name, name) == 0) // for sections
{
@ -438,36 +478,38 @@ void ElfLinker::defineSymbol(const char *name, unsigned value)
}
else
{
printf("symbol '%s' already defined\n", name);
printf("defineSymbol: symbol '%s' already defined\n", name);
abort();
}
}
// debugging support
void ElfLinker::dumpSymbols(FILE *fp) const
void ElfLinker::dumpSymbols(unsigned flags, FILE *fp) const
{
if (fp == NULL)
fp = stdout;
for (unsigned ic = 0; ic < nsymbols; ic++)
{
Symbol *symbol = symbols[ic];
fprintf(fp, "%-20s 0x%08x | %-20s 0x%08x\n",
const Symbol *symbol = symbols[ic];
if ((flags & 1) && symbol->section->output == NULL)
continue;
fprintf(fp, "%-28s 0x%08x | %-28s 0x%08x\n",
symbol->name, symbol->offset, symbol->section->name, symbol->section->offset);
}
}
unsigned ElfLinker::getSymbolOffset(const char *name) const
{
assert(frozen);
Symbol *symbol = const_cast<ElfLinker *>(this)->findSymbol(name);
const Symbol *symbol = findSymbol(name);
if (symbol->section->output == NULL)
return 0xdeaddead;
return symbol->section->offset + symbol->offset;
}
void ElfLinker::alignWithByte(unsigned len, upx_byte b)
void ElfLinker::alignWithByte(unsigned len, unsigned char b)
{
memset(output + outputlen, b, len);
outputlen += len;
}
void ElfLinker::relocate1(const Relocation *rel, upx_byte *,
@ -483,6 +525,23 @@ void ElfLinker::relocate1(const Relocation *rel, upx_byte *,
// FIXME: add more displacment overflow checks
**************************************************************************/
#if 0 // FIXME
static void check8(const Relocation *rel, const upx_byte *location, int v, int d)
{
if (v < -128 || v > 127) {
printf("value out of range (%d) in reloc %s:%x\n",
v, rel->section->name, rel->offset);
abort();
}
if (d < -128 || d > 127) {
printf("displacement target out of range (%d) in reloc %s:%x\n",
v, rel->section->name, rel->offset);
abort();
}
}
#endif
void ElfLinkerAMD64::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type)
{
@ -580,6 +639,7 @@ void ElfLinkerM68k::alignCode(unsigned len)
assert((outputlen & 1) == 0);
for (unsigned i = 0; i < len; i += 2)
set_be16(output + outputlen + i, 0x4e71); // "nop"
outputlen += len;
}
void ElfLinkerM68k::relocate1(const Relocation *rel, upx_byte *location,
@ -651,12 +711,12 @@ void ElfLinkerX86::relocate1(const Relocation *rel, upx_byte *location,
return super::relocate1(rel, location, value, type);
type += 6;
int range_check = 0;
bool range_check = false;
if (strncmp(type, "PC", 2) == 0)
{
value -= rel->section->offset + rel->offset;
type += 2;
range_check = 1;
range_check = true;
}
if (strcmp(type, "8") == 0)

View File

@ -41,8 +41,6 @@ protected:
struct Symbol;
struct Relocation;
bool frozen; // FIXME: can we remove this ?
upx_byte *input;
int inputlen;
upx_byte *output;
@ -62,11 +60,13 @@ protected:
unsigned nrelocations;
unsigned nrelocations_capacity;
bool reloc_done;
void preprocessSections(char *start, const char *end);
void preprocessSymbols(char *start, const char *end);
void preprocessRelocations(char *start, const char *end);
Section *findSection(const char *name) const;
Symbol *findSymbol(const char *name) /*const*/;
Section *findSection(const char *name, bool fatal=true) const;
Symbol *findSymbol(const char *name, bool fatal=true) const;
Symbol *addSymbol(const char *name, const char *section, unsigned offset);
Relocation *addRelocation(const char *section, unsigned off, const char *type,
@ -79,16 +79,16 @@ public:
virtual void init(const void *pdata, int plen);
virtual void setLoaderAlignOffset(int phase);
virtual int addLoader(const char *sname);
virtual void addSection(const char *sname, const void *sdata, int slen, int align);
virtual void freeze();
virtual int getSection(const char *sname, int *slen=NULL);
virtual upx_byte *getLoader(int *llen=NULL);
virtual Section *addSection(const char *sname, const void *sdata, int slen, unsigned p2align);
virtual int getSection(const char *sname, int *slen=NULL) const;
virtual int getSectionSize(const char *sname) const;
virtual upx_byte *getLoader(int *llen=NULL) const;
virtual void relocate();
virtual void defineSymbol(const char *name, unsigned value);
virtual unsigned getSymbolOffset(const char *) const;
virtual void dumpSymbols(FILE *fp=NULL) const;
virtual void dumpSymbols(unsigned flags=0, FILE *fp=NULL) const;
void alignWithByte(unsigned len, upx_byte b);
void alignWithByte(unsigned len, unsigned char b);
virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
virtual void alignData(unsigned len) { alignWithByte(len, 0); }
@ -104,7 +104,7 @@ struct ElfLinker::Section : private nocopy
upx_byte *output;
unsigned size;
unsigned offset;
unsigned char align; // log2
unsigned p2align; // log2
Section *next;
Section(const char *n, const void *i, unsigned s, unsigned a=0);

View File

@ -932,12 +932,6 @@ unsigned Packer::unoptimizeReloc32(upx_byte **in, upx_byte *image,
// loader util
**************************************************************************/
void Packer::freezeLoader()
{
linker->freeze();
}
upx_byte *Packer::getLoader() const
{
int size = -1;
@ -1034,6 +1028,12 @@ void Packer::initLoader(const void *pdata, int plen, int small)
}
void Packer::addLoader(const char *s)
{
if (s && *s)
linker->addLoader(s);
}
void __acc_cdecl_va Packer::addLoader(const char *s, ...)
{
va_list ap;

View File

@ -206,14 +206,16 @@ protected:
virtual int buildLoader(const Filter *ft) = 0;
virtual Linker* newLinker() const = 0;
// loader util for linker
virtual void freezeLoader();
void freezeLoader() { }
virtual upx_byte *getLoader() const;
virtual int getLoaderSize() const;
virtual void initLoader(const void *pdata, int plen, int small=-1);
#if 1 && (ACC_CC_GNUC >= 0x040100)
virtual void __acc_cdecl_va addLoader(const char *s, ...) __attribute__((__sentinel__));
virtual void addLoader(const char *);
virtual void __acc_cdecl_va addLoader(const char *, ...) __attribute__((__sentinel__));
#else
virtual void __acc_cdecl_va addLoader(const char *s, ...);
virtual void addLoader(const char *);
virtual void __acc_cdecl_va addLoader(const char *, ...);
#endif
virtual int getLoaderSection(const char *name, int *slen=NULL) const;
virtual int getLoaderSectionStart(const char *name, int *slen=NULL) const;