added full support for 64-bit relocations

This commit is contained in:
László Molnár
2013-08-22 21:43:11 +02:00
parent 893f26ac9a
commit 037c29d24a
2 changed files with 52 additions and 50 deletions
+34 -33
View File
@@ -84,7 +84,7 @@ ElfLinker::Section::~Section()
// Symbol // Symbol
**************************************************************************/ **************************************************************************/
ElfLinker::Symbol::Symbol(const char *n, Section *s, unsigned o) : ElfLinker::Symbol::Symbol(const char *n, Section *s, u64 o) :
name(NULL), section(s), offset(o) name(NULL), section(s), offset(o)
{ {
name = strdup(n); name = strdup(n);
@@ -103,7 +103,7 @@ ElfLinker::Symbol::~Symbol()
**************************************************************************/ **************************************************************************/
ElfLinker::Relocation::Relocation(const Section *s, unsigned o, const char *t, ElfLinker::Relocation::Relocation(const Section *s, unsigned o, const char *t,
const Symbol *v, unsigned a) : const Symbol *v, u64 a) :
section(s), offset(o), type(t), value(v), add(a) section(s), offset(o), type(t), value(v), add(a)
{ {
assert(section != NULL); assert(section != NULL);
@@ -294,29 +294,28 @@ void ElfLinker::preprocessRelocations(char *start, char *end)
char *t = strstr(start, type); char *t = strstr(start, type);
t[strlen(type)] = 0; t[strlen(type)] = 0;
unsigned add = 0; u64 add = 0;
if (char *p = strstr(symbol, "+0x")) char *p = strstr(symbol, "+0x");
if (p == NULL)
p = strstr(symbol, "-0x");
if (p)
{ {
char sign = *p;
*p = 0; // terminate the symbol name *p = 0; // terminate the symbol name
p += 3; p += 3;
if (strlen(p) == 16) { assert(strlen(p) == 8 || strlen(p) == 16);
// skip 8 leading chars if sign of char 9 matches
if (memcmp(p, "000000000", 9))
p += 8;
else if (memcmp(p, "fffffffff", 9))
p += 8;
}
assert(strlen(p) == 8);
char *endptr = NULL; char *endptr = NULL;
unsigned long ul = strtoul(p, &endptr, 16); unsigned long long ull = strtoull(p, &endptr, 16);
add = (unsigned) ul; add = (u64) ull;
assert(add == ul); assert(add == ull);
assert(endptr && *endptr == '\0'); assert(endptr && *endptr == '\0');
if (sign == '-')
add = -add;
} }
addRelocation(section->name, offset, t, symbol, add); addRelocation(section->name, offset, t, symbol, add);
//printf("relocation %s %s %x %d preprocessed\n", section->name, symbol, offset, add); //printf("relocation %s %s %x %llu preprocessed\n", section->name, symbol, offset, (unsigned long long) add);
} }
start = nextl + 1; start = nextl + 1;
@@ -372,7 +371,7 @@ ElfLinker::Symbol *ElfLinker::addSymbol(const char *name, const char *section,
ElfLinker::Relocation *ElfLinker::addRelocation(const char *section, unsigned off, ElfLinker::Relocation *ElfLinker::addRelocation(const char *section, unsigned off,
const char *type, const char *symbol, const char *type, const char *symbol,
unsigned add) u64 add)
{ {
if (update_capacity(nrelocations, &nrelocations_capacity)) if (update_capacity(nrelocations, &nrelocations_capacity))
relocations = static_cast<Relocation **>(realloc(relocations, (nrelocations_capacity) * sizeof(Relocation *))); relocations = static_cast<Relocation **>(realloc(relocations, (nrelocations_capacity) * sizeof(Relocation *)));
@@ -498,7 +497,7 @@ void ElfLinker::relocate()
for (unsigned ic = 0; ic < nrelocations; ic++) for (unsigned ic = 0; ic < nrelocations; ic++)
{ {
const Relocation *rel = relocations[ic]; const Relocation *rel = relocations[ic];
unsigned value = 0; u64 value = 0;
if (rel->section->output == NULL) if (rel->section->output == NULL)
continue; continue;
@@ -519,13 +518,13 @@ void ElfLinker::relocate()
rel->value->offset + rel->add; rel->value->offset + rel->add;
} }
upx_byte *location = rel->section->output + rel->offset; upx_byte *location = rel->section->output + rel->offset;
//printf("%-28s %-28s %-10s 0x%08x 0x%08x\n", rel->section->name, rel->value->name, rel->type, value, value - rel->section->offset - rel->offset); //printf("%-28s %-28s %-10s 0x%16llx 0x%16llx\n", rel->section->name, rel->value->name, rel->type, (long long) value, (long long) value - rel->section->offset - rel->offset);
//printf(" %d %d %d %d %d : %d\n", value, rel->value->section->offset, rel->value->offset, rel->offset, rel->add, *location); //printf(" %llx %d %llx %d %llx : %d\n", (long long) value, rel->value->section->offset, rel->value->offset, rel->offset, (long long) rel->add, *location);
relocate1(rel, location, value, rel->type); relocate1(rel, location, value, rel->type);
} }
} }
void ElfLinker::defineSymbol(const char *name, unsigned value) void ElfLinker::defineSymbol(const char *name, u64 value)
{ {
Symbol *symbol = findSymbol(name); Symbol *symbol = findSymbol(name);
if (strcmp(symbol->section->name, "*ABS*") == 0) if (strcmp(symbol->section->name, "*ABS*") == 0)
@@ -550,8 +549,8 @@ void ElfLinker::dumpSymbol(const Symbol *symbol, unsigned flags, FILE *fp) const
{ {
if ((flags & 1) && symbol->section->output == NULL) if ((flags & 1) && symbol->section->output == NULL)
return; return;
fprintf(fp, "%-28s 0x%08x | %-28s 0x%08x\n", fprintf(fp, "%-28s 0x%16llx | %-28s 0x%08x\n",
symbol->name, symbol->offset, symbol->section->name, symbol->section->offset); symbol->name, (unsigned long long) symbol->offset, symbol->section->name, symbol->section->offset);
} }
void ElfLinker::dumpSymbols(unsigned flags, FILE *fp) const void ElfLinker::dumpSymbols(unsigned flags, FILE *fp) const
{ {
@@ -594,7 +593,7 @@ void ElfLinker::alignWithByte(unsigned len, unsigned char b)
} }
void ElfLinker::relocate1(const Relocation *rel, upx_byte *, void ElfLinker::relocate1(const Relocation *rel, upx_byte *,
unsigned, const char *) u64, const char *)
{ {
internal_error("unknown relocation type '%s\n", rel->type); internal_error("unknown relocation type '%s\n", rel->type);
} }
@@ -620,7 +619,7 @@ static void check8(const Relocation *rel, const upx_byte *location, int v, int d
void ElfLinkerAMD64::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerAMD64::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strncmp(type, "R_X86_64_", 9)) if (strncmp(type, "R_X86_64_", 9))
return super::relocate1(rel, location, value, type); return super::relocate1(rel, location, value, type);
@@ -646,15 +645,17 @@ void ElfLinkerAMD64::relocate1(const Relocation *rel, upx_byte *location,
} }
else if (strcmp(type, "16") == 0) else if (strcmp(type, "16") == 0)
set_le16(location, get_le16(location) + value); set_le16(location, get_le16(location) + value);
else if (strcmp(type, "32") == 0) else if (strncmp(type, "32", 2) == 0) // for "32" and "32S"
set_le32(location, get_le32(location) + value); set_le32(location, get_le32(location) + value);
else if (strcmp(type, "64") == 0)
set_le64(location, get_le64(location) + value);
else else
super::relocate1(rel, location, value, type); super::relocate1(rel, location, value, type);
} }
void ElfLinkerArmBE::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerArmBE::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strcmp(type, "R_ARM_PC24") == 0) if (strcmp(type, "R_ARM_PC24") == 0)
{ {
@@ -689,7 +690,7 @@ void ElfLinkerArmBE::relocate1(const Relocation *rel, upx_byte *location,
void ElfLinkerArmLE::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerArmLE::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strcmp(type, "R_ARM_PC24") == 0) if (strcmp(type, "R_ARM_PC24") == 0)
{ {
@@ -733,7 +734,7 @@ void ElfLinkerM68k::alignCode(unsigned len)
} }
void ElfLinkerM68k::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerM68k::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strncmp(type, "R_68K_", 6)) if (strncmp(type, "R_68K_", 6))
return super::relocate1(rel, location, value, type); return super::relocate1(rel, location, value, type);
@@ -759,7 +760,7 @@ void ElfLinkerM68k::relocate1(const Relocation *rel, upx_byte *location,
void ElfLinkerMipsBE::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerMipsBE::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
#define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15)) #define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15))
#define MIPS_LO(a) ((a) & 0xffff) #define MIPS_LO(a) ((a) & 0xffff)
@@ -790,7 +791,7 @@ void ElfLinkerMipsBE::relocate1(const Relocation *rel, upx_byte *location,
void ElfLinkerMipsLE::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerMipsLE::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
#define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15)) #define MIPS_HI(a) (((a) >> 16) + (((a) & 0x8000) >> 15))
#define MIPS_LO(a) ((a) & 0xffff) #define MIPS_LO(a) ((a) & 0xffff)
@@ -821,7 +822,7 @@ void ElfLinkerMipsLE::relocate1(const Relocation *rel, upx_byte *location,
void ElfLinkerPpc32::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerPpc32::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strncmp(type, "R_PPC_", 6)) if (strncmp(type, "R_PPC_", 6))
return super::relocate1(rel, location, value, type); return super::relocate1(rel, location, value, type);
@@ -862,7 +863,7 @@ void ElfLinkerPpc32::relocate1(const Relocation *rel, upx_byte *location,
void ElfLinkerX86::relocate1(const Relocation *rel, upx_byte *location, void ElfLinkerX86::relocate1(const Relocation *rel, upx_byte *location,
unsigned value, const char *type) u64 value, const char *type)
{ {
if (strncmp(type, "R_386_", 6)) if (strncmp(type, "R_386_", 6))
return super::relocate1(rel, location, value, type); return super::relocate1(rel, location, value, type);
+18 -17
View File
@@ -40,6 +40,7 @@ class ElfLinker : private noncopyable
public: public:
const N_BELE_RTP::AbstractPolicy *bele; // target endianness const N_BELE_RTP::AbstractPolicy *bele; // target endianness
protected: protected:
typedef acc_uint64l_t u64;
struct Section; struct Section;
struct Symbol; struct Symbol;
struct Relocation; struct Relocation;
@@ -74,7 +75,7 @@ protected:
Symbol *addSymbol(const char *name, const char *section, unsigned offset); Symbol *addSymbol(const char *name, const char *section, unsigned offset);
Relocation *addRelocation(const char *section, unsigned off, const char *type, Relocation *addRelocation(const char *section, unsigned off, const char *type,
const char *symbol, unsigned add); const char *symbol, u64 add);
public: public:
ElfLinker(); ElfLinker();
@@ -93,7 +94,7 @@ public:
virtual int getSection(const char *sname, int *slen=NULL) const; virtual int getSection(const char *sname, int *slen=NULL) const;
virtual int getSectionSize(const char *sname) const; virtual int getSectionSize(const char *sname) const;
virtual upx_byte *getLoader(int *llen=NULL) const; virtual upx_byte *getLoader(int *llen=NULL) const;
virtual void defineSymbol(const char *name, unsigned value); virtual void defineSymbol(const char *name, u64 value);
virtual unsigned getSymbolOffset(const char *) const; virtual unsigned getSymbolOffset(const char *) const;
virtual void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const; virtual void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const;
@@ -106,15 +107,15 @@ public:
protected: protected:
virtual void relocate(); virtual void relocate();
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
// target endianness abstraction // target endianness abstraction
unsigned get_te16(const void *p) const { return bele->get16(p); } unsigned get_te16(const void *p) const { return bele->get16(p); }
unsigned get_te32(const void *p) const { return bele->get32(p); } unsigned get_te32(const void *p) const { return bele->get32(p); }
acc_uint64l_t get_te64(const void *p) const { return bele->get64(p); } u64 get_te64(const void *p) const { return bele->get64(p); }
void set_te16(void *p, unsigned v) const { bele->set16(p, v); } void set_te16(void *p, unsigned v) const { bele->set16(p, v); }
void set_te32(void *p, unsigned v) const { bele->set32(p, v); } void set_te32(void *p, unsigned v) const { bele->set32(p, v); }
void set_te64(void *p, acc_uint64l_t v) const { bele->set64(p, v); } void set_te64(void *p, u64 v) const { bele->set64(p, v); }
}; };
@@ -137,9 +138,9 @@ struct ElfLinker::Symbol : private noncopyable
{ {
char *name; char *name;
Section *section; Section *section;
unsigned offset; u64 offset;
Symbol(const char *n, Section *s, unsigned o); Symbol(const char *n, Section *s, u64 o);
~Symbol(); ~Symbol();
}; };
@@ -150,10 +151,10 @@ struct ElfLinker::Relocation : private noncopyable
unsigned offset; unsigned offset;
const char *type; const char *type;
const Symbol *value; const Symbol *value;
unsigned add; // used in .rela relocations u64 add; // used in .rela relocations
Relocation(const Section *s, unsigned o, const char *t, Relocation(const Section *s, unsigned o, const char *t,
const Symbol *v, unsigned a); const Symbol *v, u64 a);
}; };
@@ -167,7 +168,7 @@ class ElfLinkerAMD64 : public ElfLinker
protected: protected:
virtual void alignCode(unsigned len) { alignWithByte(len, 0x90); } virtual void alignCode(unsigned len) { alignWithByte(len, 0x90); }
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -178,7 +179,7 @@ public:
ElfLinkerArmBE() { bele = &N_BELE_RTP::be_policy; } ElfLinkerArmBE() { bele = &N_BELE_RTP::be_policy; }
protected: protected:
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -187,7 +188,7 @@ class ElfLinkerArmLE : public ElfLinker
typedef ElfLinker super; typedef ElfLinker super;
protected: protected:
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -199,7 +200,7 @@ public:
protected: protected:
virtual void alignCode(unsigned len); virtual void alignCode(unsigned len);
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -210,7 +211,7 @@ public:
ElfLinkerMipsBE() { bele = &N_BELE_RTP::be_policy; } ElfLinkerMipsBE() { bele = &N_BELE_RTP::be_policy; }
protected: protected:
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -219,7 +220,7 @@ class ElfLinkerMipsLE : public ElfLinker
typedef ElfLinker super; typedef ElfLinker super;
protected: protected:
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -230,7 +231,7 @@ public:
ElfLinkerPpc32() { bele = &N_BELE_RTP::be_policy; } ElfLinkerPpc32() { bele = &N_BELE_RTP::be_policy; }
protected: protected:
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };
@@ -240,7 +241,7 @@ class ElfLinkerX86 : public ElfLinker
protected: protected:
virtual void alignCode(unsigned len) { alignWithByte(len, 0x90); } virtual void alignCode(unsigned len) { alignWithByte(len, 0x90); }
virtual void relocate1(const Relocation *, upx_byte *location, virtual void relocate1(const Relocation *, upx_byte *location,
unsigned value, const char *type); u64 value, const char *type);
}; };