arm64 filter, relocation, defineSymbols

modified:   Makefile
	modified:   bele.h
	modified:   filter/ct.h
	modified:   filteri.cpp
	modified:   linker.cpp
	modified:   miniacc.h
	modified:   p_lx_elf.cpp
	modified:   stub/arm64-linux.elf-entry.h
	modified:   stub/src/arm64-linux.elf-entry.S
This commit is contained in:
John Reiser 2017-03-05 21:05:13 -08:00
parent 4089cc6e6f
commit 68a2b91ccb
9 changed files with 142 additions and 95 deletions

View File

@ -5,7 +5,7 @@
#
# build configuration options for this Makefile
BUILD_TYPE_DEBUG ?= 0
BUILD_TYPE_DEBUG ?= 1
BUILD_TYPE_SANITIZE ?= 0
BUILD_USE_DEPEND ?= 1

View File

@ -142,6 +142,24 @@ inline void set_le24(void *p, unsigned v)
#endif
}
inline unsigned get_le26(const void *p)
{
#if defined(ACC_UA_GET_LE26)
return ACC_UA_GET_LE26(p);
#else
return acc_ua_get_le26(p);
#endif
}
inline void set_le26(void *p, unsigned v)
{
#if defined(ACC_UA_SET_LE26)
ACC_UA_SET_LE26(p, v);
#else
acc_ua_set_le26(p, v);
#endif
}
inline unsigned get_le32(const void *p)
{
#if defined(ACC_UA_GET_LE32)

View File

@ -459,4 +459,45 @@ static int s_ct24arm_be(Filter *f)
#undef CT24ARM_BE
#undef ARMCT_COND
/*************************************************************************
// 26-bit ARM calltrick ("naive")
**************************************************************************/
#define CT26ARM_LE(f, cond, addvalue, get, set) \
upx_byte *b = f->buf; \
upx_byte *b_end = b + f->buf_len - 4; \
do { \
if (cond) \
{ \
unsigned a = (unsigned) (b - f->buf); \
f->lastcall = a; \
set(b, get(b) + (addvalue)); \
f->calls++; \
} \
b += 4; \
} while (b < b_end); \
if (f->lastcall) f->lastcall += 4; \
return 0;
#define ARMCT_COND (((b[3] & 0x7C) == 0x14))
static int f_ct26arm_le(Filter *f)
{
CT26ARM_LE(f, ARMCT_COND, a / 4 + f->addvalue, get_le26, set_le26)
}
static int u_ct26arm_le(Filter *f)
{
CT26ARM_LE(f, ARMCT_COND, 0 - a / 4 - f->addvalue, get_le26, set_le26)
}
static int s_ct26arm_le(Filter *f)
{
CT26ARM_LE(f, ARMCT_COND, a + f->addvalue, get_le26, set_dummy)
}
#undef CT26ARM_LE
#undef ARMCT_COND
/* vim:set ts=4 sw=4 et: */

View File

@ -228,6 +228,9 @@ const FilterImp::FilterEntry FilterImp::filters[] = {
{ 0x50, 8, 0x01ffffff, f_ct24arm_le, u_ct24arm_le, s_ct24arm_le },
{ 0x51, 8, 0x01ffffff, f_ct24arm_be, u_ct24arm_be, s_ct24arm_be },
// 26-bit calltrick for arm64
{ 0x52, 8, 0x03ffffff, f_ct26arm_le, u_ct26arm_le, s_ct26arm_le },
// 32-bit cto calltrick with jmp and jcc(swap 0x0f/0x8Y) and relative renumbering
{ 0x80, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
{ 0x81, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },

View File

@ -541,7 +541,7 @@ void ElfLinker::alignWithByte(unsigned len, unsigned char b) {
}
void ElfLinker::relocate1(const Relocation *rel, upx_byte *, upx_uint64_t, const char *) {
internal_error("unknown relocation type '%s\n", rel->type);
internal_error("unknown relocation type '%s\n'", rel->type);
}
/*************************************************************************
@ -600,14 +600,18 @@ void ElfLinkerARM64::relocate1(const Relocation *rel, upx_byte *location, upx_ui
if (!strncmp(type, "PREL", 4)) {
value -= rel->section->offset + rel->offset;
type += 4;
}
if (!strcmp(type, "16"))
set_le16(location, get_le16(location) + value);
else if (!strncmp(type, "32", 2)) // for "32" and "32S"
if (!strcmp(type, "16"))
set_le16(location, get_le16(location) + value);
else if (!strncmp(type, "32", 2)) // for "32" and "32S"
set_le32(location, get_le32(location) + value);
else if (!strcmp(type, "64"))
set_le64(location, get_le64(location) + value);
} else if (!strcmp(type, "ABS32") == 0) {
set_le32(location, get_le32(location) + value);
else if (!strcmp(type, "64"))
} else if (!strcmp(type, "ABS64") == 0) {
set_le64(location, get_le64(location) + value);
}
else
super::relocate1(rel, location, value, type);
}

View File

@ -5065,9 +5065,11 @@ ACCLIB_EXTERN(void, acc_ua_set_be24) (acc_hvoid_p, acc_uint32l_t);
ACCLIB_EXTERN(void, acc_ua_set_be32) (acc_hvoid_p, acc_uint32l_t);
ACCLIB_EXTERN(unsigned, acc_ua_get_le16) (const acc_hvoid_p);
ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p);
ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le26) (const acc_hvoid_p);
ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p);
ACCLIB_EXTERN(void, acc_ua_set_le16) (acc_hvoid_p, unsigned);
ACCLIB_EXTERN(void, acc_ua_set_le24) (acc_hvoid_p, acc_uint32l_t);
ACCLIB_EXTERN(void, acc_ua_set_le26) (acc_hvoid_p, acc_uint32l_t);
ACCLIB_EXTERN(void, acc_ua_set_le32) (acc_hvoid_p, acc_uint32l_t);
#if defined(acc_int64l_t)
ACCLIB_EXTERN(acc_uint64l_t, acc_ua_get_be64) (const acc_hvoid_p);
@ -6057,6 +6059,12 @@ ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p p)
const acc_hbyte_p b = ACC_CCAST(const acc_hbyte_p, p);
return ACC_ICONV(acc_uint32l_t, b[0]) | (ACC_ICONV(acc_uint32l_t, b[1]) << 8) | (ACC_ICONV(acc_uint32l_t, b[2]) << 16);
}
ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le26) (const acc_hvoid_p p)
{
const acc_hbyte_p b = ACC_CCAST(const acc_hbyte_p, p);
return ACC_ICONV(acc_uint32l_t, b[0] ) | ( ACC_ICONV(acc_uint32l_t, b[1]) << 8) |
(ACC_ICONV(acc_uint32l_t, b[2]) << 16) | (((ACC_ICONV(acc_uint32l_t, b[3]) & 3)<< 24));
}
ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p p)
{
#if defined(ACC_UA_GET_LE32)
@ -6083,6 +6091,14 @@ ACCLIB_PUBLIC(void, acc_ua_set_le24) (acc_hvoid_p p, acc_uint32l_t v)
b[1] = ACC_ICONV(unsigned char, (v >> 8) & 0xff);
b[2] = ACC_ICONV(unsigned char, (v >> 16) & 0xff);
}
ACCLIB_PUBLIC(void, acc_ua_set_le26) (acc_hvoid_p p, acc_uint32l_t v)
{
acc_hbyte_p b = ACC_PCAST(acc_hbyte_p, p);
b[0] = ACC_ICONV(unsigned char, (v >> 0) & 0xff);
b[1] = ACC_ICONV(unsigned char, (v >> 8) & 0xff);
b[2] = ACC_ICONV(unsigned char, (v >> 16) & 0xff);
b[3] = ACC_ICONV(unsigned char, (v >> 24) & 0x03) | (0xFC & b[3]);
}
ACCLIB_PUBLIC(void, acc_ua_set_le32) (acc_hvoid_p p, acc_uint32l_t v)
{
#if defined(ACC_UA_SET_LE32)

View File

@ -705,7 +705,7 @@ int const *
PackLinuxElf64arm::getFilters() const
{
static const int filters[] = {
0x4A,
0x52,
FT_END };
return filters;
}
@ -1118,85 +1118,6 @@ PackLinuxElf64amd::defineSymbols(Filter const *)
//linker->dumpSymbols(); // debug
}
void
PackLinuxElf64arm::defineSymbols(Filter const *)
{
unsigned const hlen = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info);
// We want to know if compressed data, plus stub, plus a couple pages,
// will fit below the uncompressed program in memory. But we don't
// know the final total compressed size yet, so use the uncompressed
// size (total over all PT_LOAD64) as an upper bound.
unsigned len = 0;
upx_uint64_t lo_va_user = ~0ull; // infinity
for (int j= e_phnum; --j>=0; ) {
if (PT_LOAD64 == get_te32(&phdri[j].p_type)) {
len += (unsigned)get_te64(&phdri[j].p_filesz);
upx_uint64_t const va = get_te64(&phdri[j].p_vaddr);
if (va < lo_va_user) {
lo_va_user = va;
}
}
}
lsize = /*getLoaderSize()*/ 64 * 1024; // XXX: upper bound; avoid circularity
upx_uint64_t lo_va_stub = get_te64(&elfout.phdr[0].p_vaddr);
upx_uint64_t adrc;
upx_uint64_t adrm;
upx_uint64_t adru;
upx_uint64_t adrx;
unsigned cntc;
unsigned lenm;
unsigned lenu;
len += (7&-lsize) + lsize;
is_big = (lo_va_user < (lo_va_stub + len + 2*page_size));
if (is_big && ehdri.ET_EXEC==get_te16(&ehdri.e_type)) {
set_te64( &elfout.ehdr.e_entry,
get_te64(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub);
set_te64(&elfout.phdr[0].p_vaddr, lo_va_user);
set_te64(&elfout.phdr[0].p_paddr, lo_va_user);
lo_va_stub = lo_va_user;
adrc = lo_va_stub;
adrm = getbrk(phdri, e_phnum);
adru = page_mask & (~page_mask + adrm); // round up to page boundary
adrx = adru + hlen;
lenm = page_size + len;
lenu = page_size + len;
cntc = len >> 3; // over-estimate; corrected at runtime
}
else {
adrm = lo_va_stub + len;
adrc = adrm;
adru = lo_va_stub;
adrx = lo_va_stub + hlen;
lenm = page_size;
lenu = page_size + len;
cntc = 0;
}
adrm = page_mask & (~page_mask + adrm); // round up to page boundary
adrc = page_mask & (~page_mask + adrc); // round up to page boundary
//linker->defineSymbol("ADRX", adrx); // compressed input for eXpansion
ACC_UNUSED(adrx);
// For actual moving, we need the true count, which depends on sz_pack2
// and is not yet known. So the runtime stub detects "no move"
// if adrm==adrc, and otherwise uses actual sz_pack2 to compute cntc.
//linker->defineSymbol("CNTC", cntc); // count for copy
ACC_UNUSED(cntc);
linker->defineSymbol("LENU", lenu); // len for unmap
linker->defineSymbol("ADRC", adrc); // addr for copy
//linker->defineSymbol("ADRU", adru); // addr for unmap
ACC_UNUSED(adru);
#define EI_NIDENT 16 /* <elf.h> */
linker->defineSymbol("JMPU", EI_NIDENT -4 + lo_va_user); // unmap trampoline
#undef EI_NIDENT
linker->defineSymbol("LENM", lenm); // len for map
linker->defineSymbol("ADRM", adrm); // addr for map
//linker->dumpSymbols(); // debug
}
static const
#include "stub/i386-linux.elf-entry.h"
static const
@ -3329,6 +3250,51 @@ void PackLinuxElf32armBe::defineSymbols(Filter const *ft)
ARM_defineSymbols(ft);
}
void PackLinuxElf64arm::defineSymbols(Filter const * /*ft*/)
{
lsize = /*getLoaderSize()*/ 4 * 1024; // upper bound; avoid circularity
unsigned lo_va_user = ~0u; // infinity
for (int j= e_phnum; --j>=0; ) {
if (PT_LOAD64 == get_te64(&phdri[j].p_type)) {
unsigned const va = get_te64(&phdri[j].p_vaddr);
if (va < lo_va_user) {
lo_va_user = va;
}
}
}
unsigned lo_va_stub = get_te64(&elfout.phdr[0].p_vaddr);
unsigned adrc = 0; // init: pacify c++-analyzer
unsigned adrm = 0; // init: pacify c++-analyzer
is_big = true; // kernel disallows mapping below 0x8000.
if (is_big) {
set_te64( &elfout.ehdr.e_entry, linker->getSymbolOffset("_start") +
get_te64(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub);
set_te64(&elfout.phdr[0].p_vaddr, lo_va_user);
set_te64(&elfout.phdr[0].p_paddr, lo_va_user);
lo_va_stub = lo_va_user;
adrc = lo_va_stub;
adrm = getbrk(phdri, e_phnum);
}
adrc = page_mask & (~page_mask + adrc); // round up to page boundary
adrm = page_mask & (~page_mask + adrm); // round up to page boundary
adrm += page_size; // Try: hole so that kernel does not extend the brk(0)
linker->defineSymbol("ADRM", adrm); // addr for map
linker->defineSymbol("CPR0", 4+ linker->getSymbolOffset("cpr0"));
linker->defineSymbol("LENF", 4+ linker->getSymbolOffset("end_decompress"));
ACC_UNUSED(adrc);
#define MAP_PRIVATE 2 /* UNIX standard */
#define MAP_FIXED 0x10 /* UNIX standard */
#define MAP_ANONYMOUS 0x20 /* UNIX standard */
#define MAP_PRIVANON 3 /* QNX anonymous private memory */
unsigned mflg = MAP_PRIVATE | MAP_ANONYMOUS;
//if (ARM_is_QNX())
// mflg = MAP_PRIVANON;
linker->defineSymbol("MFLG", mflg);
}
void PackLinuxElf32mipseb::defineSymbols(Filter const * /*ft*/)
{
unsigned const hlen = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info);

View File

@ -32,8 +32,8 @@
#define STUB_ARM64_LINUX_ELF_ENTRY_SIZE 5317
#define STUB_ARM64_LINUX_ELF_ENTRY_ADLER32 0x85fe782d
#define STUB_ARM64_LINUX_ELF_ENTRY_CRC32 0x6307b5a0
#define STUB_ARM64_LINUX_ELF_ENTRY_ADLER32 0x69217770
#define STUB_ARM64_LINUX_ELF_ENTRY_CRC32 0xb10ced92
unsigned char stub_arm64_linux_elf_entry[5317] = {
/* 0x0000 */ 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -41,9 +41,9 @@ unsigned char stub_arm64_linux_elf_entry[5317] = {
/* 0x0020 */ 0, 0, 0, 0, 0, 0, 0, 0, 8, 13, 0, 0, 0, 0, 0, 0,
/* 0x0030 */ 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 64, 0, 17, 0, 14, 0,
/* 0x0040 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x0050 */ 0, 0, 0, 0, 76,255,255, 16,129, 41, 64, 41,139, 53, 65, 41,
/* 0x0060 */ 130, 9, 64,249,107, 1, 12,139, 74, 1, 12,139, 99, 1, 64,185,
/* 0x0070 */ 137, 1, 1,203, 33, 0, 3, 11,224, 3, 2,170, 33, 4, 64,145,
/* 0x0050 */ 0, 0, 0, 0, 0, 0, 32,212, 44,255,255, 16,129, 41, 64, 41,
/* 0x0060 */ 139, 53, 65, 41,107, 1, 12,139, 74, 1, 12,139, 99, 1, 64,185,
/* 0x0070 */ 137, 1, 1,203, 33, 0, 3, 11,128, 9, 64,249, 33, 4, 64,145,
/* 0x0080 */ 3, 0,128, 82, 3, 0,130, 82,224,135,189,169,226, 15, 1,169,
/* 0x0090 */ 237, 19, 0,249,226, 0,128, 82,163, 1, 28, 50, 5, 0,128,210,
/* 0x00a0 */ 4, 0,128, 18,200, 27,128, 82, 1, 0, 0,212,192, 3, 95,214,

View File

@ -70,7 +70,7 @@ mflg:
.long MFLG // MAP_{PRIVATE|ANONYMOUS} // QNX vs linux
.xword ADRM // dst for map
_start: .globl _start
//// nop; bkpt
brk #0
/* Get some pages: enough
to duplicate the entire compressed PT_LOAD, plus 1 page, located just after
the brk() of the _un_compressed program. The address is pre-calculated
@ -89,13 +89,12 @@ _start: .globl _start
adr x12,start_params -4 // &sz_pack2
ldp w1,w10,[x12] // w1= sz_pack2; w10= LENF
ldp w11,w13,[x12,#2*4] // w11= CPRO; w13= MFLG
ldr x2,[x12,#4*4] // x2= ADRM
add x11,x11,x12 // cpr0
add x10,x10,x12 // end_decompress
ldr w3,[x11,# sz_unc]
sub x9,x12,x1 // &our_Elf64_Ehdr
add w1,w1,w3 // sz_pack2 + cpr0.sz_unc
mov x0,x2 // ADRM
ldr x0,[x12,#4*4] // ADRM
add x1,x1,# PAGE_SIZE
section LUNMP000
mov w3,#0<<12 // 0-page crumb