1 /* amd64-linux.elf-main.c -- stub loader for Linux 64-bit ELF executable
2
3 This file is part of the UPX executable compressor.
4
5 Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 1996-2020 Laszlo Molnar
7 Copyright (C) 2000-2020 John F. Reiser
8 All Rights Reserved.
9
10 UPX and the UCL library are free software; you can redistribute them
11 and/or modify them under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; see the file COPYING.
22 If not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 Markus F.X.J. Oberhumer Laszlo Molnar
26 <markus@oberhumer.com> <ezerotven+github@gmail.com>
27
28 John F. Reiser
29 <jreiser@users.sourceforge.net>
30 */
31
32
33 #include "include/linux.h"
34
35 #ifndef DEBUG //{
36 #define DEBUG 0
37 #endif //}
38
39 #if !DEBUG //{
40 #define DPRINTF(fmt, args...) /*empty*/
41 #else //}{
42 // DPRINTF is defined as an expression using "({ ... })"
43 // so that DPRINTF can be invoked inside an expression,
44 // and then followed by a comma to ignore the return value.
45 // The only complication is that percent and backslash
46 // must be doubled in the format string, because the format
47 // string is processd twice: once at compile-time by 'asm'
48 // to produce the assembled value, and once at runtime to use it.
49 #if defined(__powerpc__) //{
50 #define DPRINTF(fmt, args...) ({ \
51 char const *r_fmt; \
52 asm("bl 0f; .string \"" fmt "\"; .balign 4; 0: mflr %0" \
53 /*out*/ : "=r"(r_fmt) \
54 /* in*/ : \
55 /*und*/ : "lr"); \
56 dprintf(r_fmt, args); \
57 })
58 #elif defined(__x86_64) //}{
59 #define DPRINTF(fmt, args...) ({ \
60 char const *r_fmt; \
61 asm("call 0f; .asciz \"" fmt "\"; 0: pop %0" \
62 /*out*/ : "=r"(r_fmt) ); \
63 dprintf(r_fmt, args); \
64 })
65 #elif defined(__aarch64__) //}{
66 #define DPRINTF(fmt, args...) ({ \
67 char const *r_fmt; \
68 asm("bl 0f; .string \"" fmt "\"; .balign 4; 0: mov %0,x30" \
69 /*out*/ : "=r"(r_fmt) \
70 /* in*/ : \
71 /*und*/ : "x30"); \
72 dprintf(r_fmt, args); \
73 })
74
75 #endif //}
76
77 static int dprintf(char const *fmt, ...); // forward
78 #endif /*}*/
79
80
81 /*************************************************************************
82 // configuration section
83 **************************************************************************/
84
85 // In order to make it much easier to move this code at runtime and execute
86 // it at an address different from it load address: there must be no
87 // static data, and no string constants.
88
89 #define MAX_ELF_HDR 1024 // Elf64_Ehdr + n*Elf64_Phdr must fit in this
90
91
92 /*************************************************************************
93 // "file" util
94 **************************************************************************/
95
96 typedef struct {
97 size_t size; // must be first to match size[0] uncompressed size
98 char *buf;
99 } Extent;
100
101
102 static void
xread(Extent * x,char * buf,size_t count)103 xread(Extent *x, char *buf, size_t count)
104 {
105 DPRINTF("xread x.size=%%x x.buf=%%p buf=%%p count=%%x\\n",
106 x->size, x->buf, buf, count);
107 char *p=x->buf, *q=buf;
108 size_t j;
109 if (x->size < count) {
110 exit(127);
111 }
112 for (j = count; 0!=j--; ++p, ++q) {
113 *q = *p;
114 }
115 x->buf += count;
116 x->size -= count;
117 DPRINTF("xread done\\n",0);
118 }
119
120
121 /*************************************************************************
122 // util
123 **************************************************************************/
124
125 #if 1 //{ save space
126 #define ERR_LAB error: exit(127);
127 #define err_exit(a) goto error
128 #else //}{ save debugging time
129 #define ERR_LAB /*empty*/
130 static void
err_exit(int a)131 err_exit(int a)
132 {
133 (void)a; // debugging convenience
134 DPRINTF("err_exit %%d\\n", a);
135 exit(127);
136 }
137 #endif //}
138
139 /*************************************************************************
140 // UPX & NRV stuff
141 **************************************************************************/
142
143 typedef void f_unfilter(
144 nrv_byte *, // also addvalue
145 nrv_uint,
146 unsigned cto8, // junk in high 24 bits
147 unsigned ftid
148 );
149 typedef int f_expand(
150 const nrv_byte *, nrv_uint,
151 nrv_byte *, size_t *, unsigned );
152
153 static void
unpackExtent(Extent * const xi,Extent * const xo,f_expand * const f_exp,f_unfilter * f_unf)154 unpackExtent(
155 Extent *const xi, // input
156 Extent *const xo, // output
157 f_expand *const f_exp,
158 f_unfilter *f_unf
159 )
160 {
161 while (xo->size) {
162 DPRINTF("unpackExtent xi=(%%p %%p) xo=(%%p %%p) f_exp=%%p f_unf=%%p\\n",
163 xi->size, xi->buf, xo->size, xo->buf, f_exp, f_unf);
164 struct b_info h;
165 // Note: if h.sz_unc == h.sz_cpr then the block was not
166 // compressible and is stored in its uncompressed form.
167
168 // Read and check block sizes.
169 xread(xi, (char *)&h, sizeof(h));
170 DPRINTF("h.sz_unc=%%x h.sz_cpr=%%x h.b_method=%%x\\n",
171 h.sz_unc, h.sz_cpr, h.b_method);
172 if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
173 if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
174 err_exit(2);
175 if (xi->size != 0) // all bytes must be written
176 err_exit(3);
177 break;
178 }
179 if (h.sz_cpr <= 0) {
180 err_exit(4);
181 ERR_LAB
182 }
183 if (h.sz_cpr > h.sz_unc
184 || h.sz_unc > xo->size ) {
185 err_exit(5);
186 }
187 // Now we have:
188 // assert(h.sz_cpr <= h.sz_unc);
189 // assert(h.sz_unc > 0 && h.sz_unc <= blocksize);
190 // assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);
191
192 if (h.sz_cpr < h.sz_unc) { // Decompress block
193 size_t out_len = h.sz_unc; // EOF for lzma
194 int const j = (*f_exp)((unsigned char *)xi->buf, h.sz_cpr,
195 (unsigned char *)xo->buf, &out_len,
196 #if defined(__x86_64) //{
197 *(int *)(void *)&h.b_method
198 #elif defined(__powerpc64__) || defined(__aarch64__) //}{
199 h.b_method
200 #endif //}
201 );
202 if (j != 0 || out_len != (nrv_uint)h.sz_unc) {
203 DPRINTF("j=%%x out_len=%%x &h=%%p\\n", j, out_len, &h);
204 err_exit(7);
205 }
206 // Skip Ehdr+Phdrs: separate 1st block, not filtered
207 if (h.b_ftid!=0 && f_unf // have filter
208 && ((512 < out_len) // this block is longer than Ehdr+Phdrs
209 || (xo->size==(unsigned)h.sz_unc) ) // block is last in Extent
210 ) {
211 (*f_unf)((unsigned char *)xo->buf, out_len, h.b_cto8, h.b_ftid);
212 }
213 xi->buf += h.sz_cpr;
214 xi->size -= h.sz_cpr;
215 }
216 else { // copy literal block
217 xread(xi, xo->buf, h.sz_cpr);
218 }
219 xo->buf += h.sz_unc;
220 xo->size -= h.sz_unc;
221 }
222 }
223
224 #if defined(__x86_64__) //{
225 static void *
make_hatch_x86_64(Elf64_Phdr const * const phdr,Elf64_Addr reloc,unsigned const frag_mask)226 make_hatch_x86_64(
227 Elf64_Phdr const *const phdr,
228 Elf64_Addr reloc,
229 unsigned const frag_mask
230 )
231 {
232 unsigned xprot = 0;
233 unsigned *hatch = 0;
234 DPRINTF("make_hatch %%p %%x %%x\\n",phdr,reloc,frag_mask);
235 if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
236 if (
237 // Try page fragmentation just beyond .text .
238 ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr + reloc)),
239 ( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
240 && (1*4)<=(frag_mask & -(int)(size_t)hatch) ) ) // space left on page
241 // Try Elf64_Ehdr.e_ident[12..15] . warning: 'const' cast away
242 || ( (hatch = (void *)(&((Elf64_Ehdr *)(phdr->p_vaddr + reloc))->e_ident[12])),
243 (phdr->p_offset==0) )
244 // Allocate and use a new page.
245 || ( xprot = 1, hatch = mmap(0, PAGE_SIZE, PROT_WRITE|PROT_READ,
246 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) )
247 )
248 {
249 hatch[0] = 0xc35a050f; // syscall; pop %rdx; ret
250 if (xprot) {
251 mprotect(hatch, 1*sizeof(unsigned), PROT_EXEC|PROT_READ);
252 }
253 }
254 else {
255 hatch = 0;
256 }
257 }
258 return hatch;
259 }
260 #elif defined(__powerpc64__) //}{
261 static unsigned
ORRX(unsigned ra,unsigned rs,unsigned rb)262 ORRX(unsigned ra, unsigned rs, unsigned rb) // or ra,rs,rb
263 {
264 return (31<<26) | ((037&(rs))<<21) | ((037&(ra))<<16) | ((037&(rb))<<11) | (444<<1) | 0;
265 }
266
267 static void *
make_hatch_ppc64(Elf64_Phdr const * const phdr,Elf64_Addr reloc,unsigned const frag_mask)268 make_hatch_ppc64(
269 Elf64_Phdr const *const phdr,
270 Elf64_Addr reloc,
271 unsigned const frag_mask
272 )
273 {
274 unsigned xprot = 0;
275 unsigned *hatch = 0;
276 DPRINTF("make_hatch %%p %%x %%x\\n",phdr,reloc,frag_mask);
277 if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
278 if (
279 // Try page fragmentation just beyond .text .
280 ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr + reloc)),
281 ( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
282 && (3*4)<=(frag_mask & -(int)(size_t)hatch) ) ) // space left on page
283 // Try Elf64_Phdr[1].p_paddr (2 instr) and .p_filesz (1 instr)
284 || ( (hatch = (void *)(&((Elf64_Phdr *)(1+ // Ehdr and Phdr are contiguous
285 ((Elf64_Ehdr *)(phdr->p_vaddr + reloc))))[1].p_paddr)),
286 (phdr->p_offset==0) )
287 // Allocate and use a new page.
288 || ( xprot = 1, hatch = mmap(0, 1<<12, PROT_WRITE|PROT_READ,
289 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) )
290 )
291 {
292 hatch[0]= 0x44000002; // sc
293 hatch[1]= ORRX(12,31,31); // movr r12,r31 ==> or r12,r31,r31
294 hatch[2]= 0x4e800020; // blr
295 if (xprot) {
296 mprotect(hatch, 3*sizeof(unsigned), PROT_EXEC|PROT_READ);
297 }
298 }
299 else {
300 hatch = 0;
301 }
302 }
303 return hatch;
304 }
305 #elif defined(__aarch64__) //{
306 static void *
make_hatch_arm64(Elf64_Phdr const * const phdr,uint64_t const reloc,unsigned const frag_mask)307 make_hatch_arm64(
308 Elf64_Phdr const *const phdr,
309 uint64_t const reloc,
310 unsigned const frag_mask
311 )
312 {
313 unsigned xprot = 0;
314 unsigned *hatch = 0;
315 //DPRINTF((STR_make_hatch(),phdr,reloc));
316 if (phdr->p_type==PT_LOAD && phdr->p_flags & PF_X) {
317 // The format of the 'if' is
318 // if ( ( (hatch = loc1), test_loc1 )
319 // || ( (hatch = loc2), test_loc2 ) ) {
320 // action
321 // }
322 // which uses the comma to save bytes when test_locj involves locj
323 // and the action is the same when either test succeeds.
324
325 if (
326 // Try page fragmentation just beyond .text .
327 ( (hatch = (void *)(~3ul & (3+ phdr->p_memsz + phdr->p_vaddr + reloc))),
328 ( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
329 && (2*4)<=(frag_mask & -(int)(uint64_t)hatch) ) ) // space left on page
330 // Try Elf64_Ehdr.e_ident[8..15] . warning: 'const' cast away
331 || ( (hatch = (void *)(&((Elf64_Ehdr *)(phdr->p_vaddr + reloc))->e_ident[8])),
332 (phdr->p_offset==0) )
333 // Allocate and use a new page.
334 || ( xprot = 1, hatch = mmap(0, 1<<12, PROT_WRITE|PROT_READ,
335 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) )
336 )
337 {
338 hatch[0] = 0xd4000001; // svc #0
339 hatch[1] = 0xd65f03c0; // ret (jmp *lr)
340 if (xprot) {
341 mprotect(hatch, 2*sizeof(unsigned), PROT_EXEC|PROT_READ);
342 }
343 }
344 else {
345 hatch = 0;
346 }
347 }
348 return hatch;
349 }
350 #endif //}
351
352 #if defined(__powerpc64__) || defined(__aarch64__) //{ bzero
353 static void
upx_bzero(char * p,size_t len)354 upx_bzero(char *p, size_t len)
355 {
356 DPRINTF("bzero %%x %%x\\n", p, len);
357 if (len) do {
358 *p++= 0;
359 } while (--len);
360 }
361 #define bzero upx_bzero
362 #else //}{
363 #define bzero(a,b) __builtin_memset(a,0,b)
364 #endif //}
365
366 static void
auxv_up(Elf64_auxv_t * av,unsigned const type,uint64_t const value)367 auxv_up(Elf64_auxv_t *av, unsigned const type, uint64_t const value)
368 {
369 if (!av || (1& (size_t)av)) { // none, or inhibited for PT_INTERP
370 return;
371 }
372 DPRINTF("\\nauxv_up %%d %%p\\n", type, value);
373 for (;; ++av) {
374 DPRINTF(" %%d %%p\\n", av->a_type, av->a_un.a_val);
375 if (av->a_type==type || (av->a_type==AT_IGNORE && type!=AT_NULL)) {
376 av->a_type = type;
377 av->a_un.a_val = value;
378 return;
379 }
380 if (av->a_type==AT_NULL) {
381 // We can't do this as part of the for loop because we overwrite
382 // AT_NULL too.
383 return;
384 }
385 }
386 }
387
388 // The PF_* and PROT_* bits are {1,2,4}; the conversion table fits in 32 bits.
389 #define REP8(x) \
390 ((x)|((x)<<4)|((x)<<8)|((x)<<12)|((x)<<16)|((x)<<20)|((x)<<24)|((x)<<28))
391 #define EXP8(y) \
392 ((1&(y)) ? 0xf0f0f0f0 : (2&(y)) ? 0xff00ff00 : (4&(y)) ? 0xffff0000 : 0)
393 #define PF_TO_PROT(pf) \
394 ((PROT_READ|PROT_WRITE|PROT_EXEC) & ( \
395 ( (REP8(PROT_EXEC ) & EXP8(PF_X)) \
396 |(REP8(PROT_READ ) & EXP8(PF_R)) \
397 |(REP8(PROT_WRITE) & EXP8(PF_W)) \
398 ) >> ((pf & (PF_R|PF_W|PF_X))<<2) ))
399
400
401 // Find convex hull of PT_LOAD (the minimal interval which covers all PT_LOAD),
402 // and mmap that much, to be sure that a kernel using exec-shield-randomize
403 // won't place the first piece in a way that leaves no room for the rest.
404 static Elf64_Addr // returns relocation constant
xfind_pages(unsigned mflags,Elf64_Phdr const * phdr,int phnum,Elf64_Addr * const p_brk,Elf64_Addr const elfaddr,size_t const PAGE_MASK)405 xfind_pages(unsigned mflags, Elf64_Phdr const *phdr, int phnum,
406 Elf64_Addr *const p_brk
407 , Elf64_Addr const elfaddr
408 #if defined(__powerpc64__) || defined(__aarch64__)
409 , size_t const PAGE_MASK
410 #endif
411 )
412 {
413 Elf64_Addr lo= ~0, hi= 0, addr= 0;
414 mflags += MAP_PRIVATE | MAP_ANONYMOUS; // '+' can optimize better than '|'
415 DPRINTF("xfind_pages %%x %%p %%d %%p %%p\\n", mflags, phdr, phnum, elfaddr, p_brk);
416 for (; --phnum>=0; ++phdr) if (PT_LOAD==phdr->p_type) {
417 if (phdr->p_vaddr < lo) {
418 lo = phdr->p_vaddr;
419 }
420 if (hi < (phdr->p_memsz + phdr->p_vaddr)) {
421 hi = phdr->p_memsz + phdr->p_vaddr;
422 }
423 }
424 lo -= ~PAGE_MASK & lo; // round down to page boundary
425 hi = PAGE_MASK & (hi - lo - PAGE_MASK -1); // page length
426 if (MAP_FIXED & mflags) {
427 addr = lo;
428 }
429 else if (0==lo) { // -pie ET_DYN
430 addr = elfaddr;
431 if (addr) {
432 mflags |= MAP_FIXED;
433 }
434 }
435 DPRINTF(" addr=%%p lo=%%p hi=%%p\\n", addr, lo, hi);
436 // PROT_WRITE allows testing of 64k pages on 4k Linux
437 addr = (Elf64_Addr)mmap((void *)addr, hi, (DEBUG ? PROT_WRITE : PROT_NONE), // FIXME XXX EVIL
438 mflags, -1, 0);
439 DPRINTF(" addr=%%p\\n", addr);
440 *p_brk = hi + addr; // the logical value of brk(0)
441 return (Elf64_Addr)(addr - lo);
442 }
443
444 static Elf64_Addr // entry address
do_xmap(Elf64_Ehdr const * const ehdr,Extent * const xi,int const fdi,Elf64_auxv_t * const av,f_expand * const f_exp,f_unfilter * const f_unf,Elf64_Addr * p_reloc,size_t const PAGE_MASK)445 do_xmap(
446 Elf64_Ehdr const *const ehdr,
447 Extent *const xi,
448 int const fdi,
449 Elf64_auxv_t *const av,
450 f_expand *const f_exp,
451 f_unfilter *const f_unf,
452 Elf64_Addr *p_reloc
453 #if defined(__powerpc64__) || defined(__aarch64__)
454 , size_t const PAGE_MASK
455 #endif
456 )
457 {
458 Elf64_Phdr const *phdr = (Elf64_Phdr const *)(void const *)(ehdr->e_phoff +
459 (char const *)ehdr);
460 Elf64_Addr v_brk;
461 Elf64_Addr const reloc = xfind_pages(
462 ((ET_DYN!=ehdr->e_type) ? MAP_FIXED : 0), phdr, ehdr->e_phnum, &v_brk
463 , *p_reloc
464 #if defined(__powerpc64__) || defined(__aarch64__)
465 , PAGE_MASK
466 #endif
467 );
468 DPRINTF("do_xmap reloc=%%p\\n", reloc);
469 int j;
470 for (j=0; j < ehdr->e_phnum; ++phdr, ++j)
471 if (xi && PT_PHDR==phdr->p_type) {
472 auxv_up(av, AT_PHDR, phdr->p_vaddr + reloc);
473 } else
474 if (PT_LOAD==phdr->p_type) {
475 if (xi && !phdr->p_offset /*&& ET_EXEC==ehdr->e_type*/) { // 1st PT_LOAD
476 // ? Compressed PT_INTERP must not overwrite values from compressed a.out?
477 auxv_up(av, AT_PHDR, phdr->p_vaddr + reloc + ehdr->e_phoff);
478 auxv_up(av, AT_PHNUM, ehdr->e_phnum);
479 auxv_up(av, AT_PHENT, ehdr->e_phentsize); /* ancient kernels might omit! */
480 //auxv_up(av, AT_PAGESZ, PAGE_SIZE); /* ld-linux.so.2 does not need this */
481 }
482 unsigned const prot = PF_TO_PROT(phdr->p_flags);
483 Extent xo;
484 size_t mlen = xo.size = phdr->p_filesz;
485 char *addr = xo.buf = reloc + (char *)phdr->p_vaddr;
486 char *haddr = phdr->p_memsz + addr;
487 size_t frag = (size_t)addr &~ PAGE_MASK;
488 mlen += frag;
489 addr -= frag;
490
491 if (addr != mmap(addr, mlen, prot | (xi ? PROT_WRITE : 0),
492 MAP_FIXED | MAP_PRIVATE | (xi ? MAP_ANONYMOUS : 0),
493 (xi ? -1 : fdi), phdr->p_offset - frag) ) {
494 err_exit(8);
495 }
496 if (xi) {
497 unpackExtent(xi, &xo, f_exp, f_unf);
498 }
499 // Linux does not fixup the low end, so neither do we.
500 //if (PROT_WRITE & prot) {
501 // bzero(addr, frag); // fragment at lo end
502 //}
503 frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
504 if (PROT_WRITE & prot) { // note: read-only .bss not supported here
505 bzero(mlen+addr, frag); // fragment at hi end
506 }
507 if (xi) {
508 #if defined(__x86_64) //{
509 void *const hatch = make_hatch_x86_64(phdr, reloc, ~PAGE_MASK);
510 #elif defined(__powerpc64__) //}{
511 void *const hatch = make_hatch_ppc64(phdr, reloc, ~PAGE_MASK);
512 #elif defined(__aarch64__) //}{
513 void *const hatch = make_hatch_arm64(phdr, reloc, ~PAGE_MASK);
514 #endif //}
515 if (0!=hatch) {
516 auxv_up((Elf64_auxv_t *)(~1 & (size_t)av), AT_NULL, (size_t)hatch);
517 }
518 if (0!=mprotect(addr, mlen, prot)) {
519 err_exit(10);
520 ERR_LAB
521 }
522 }
523 addr += mlen + frag; /* page boundary on hi end */
524 if (addr < haddr) { // need pages for .bss
525 if (addr != mmap(addr, haddr - addr, prot,
526 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 ) ) {
527 err_exit(9);
528 }
529 }
530 }
531 if (xi) { // 1st call (main); also have (0!=av) here
532 if (ET_DYN!=ehdr->e_type) {
533 // Needed only if compressed shell script invokes compressed shell.
534 // brk(v_brk); // SIGSEGV when is_big [unmaps ourself!]
535 }
536 }
537 if (p_reloc) {
538 *p_reloc = reloc;
539 }
540 return ehdr->e_entry + reloc;
541 }
542
543
544 /*************************************************************************
545 // upx_main - called by our entry code
546 //
547 // This function is optimized for size.
548 **************************************************************************/
549
550 void *
upx_main(struct b_info const * const bi,size_t const sz_compressed,Elf64_Ehdr * const ehdr,Elf64_auxv_t * const av,f_expand * const f_exp,f_unfilter * const f_unf,Elf64_Addr elfaddr)551 upx_main( // returns entry address
552 struct b_info const *const bi, // 1st block header
553 size_t const sz_compressed, // total length
554 Elf64_Ehdr *const ehdr, // temp char[sz_ehdr] for decompressing
555 Elf64_auxv_t *const av,
556 f_expand *const f_exp,
557 f_unfilter *const f_unf
558 #if defined(__x86_64) //{
559 , Elf64_Addr elfaddr // In: &Elf64_Ehdr for stub
560 #elif defined(__powerpc64__) //}{
561 , Elf64_Addr *p_reloc // In: &Elf64_Ehdr for stub; Out: 'slide' for PT_INTERP
562 , size_t const PAGE_MASK
563 #elif defined(__aarch64__) //}{
564 , Elf64_Addr elfaddr
565 , size_t const PAGE_MASK
566 #endif //}
567 )
568 {
569 Extent xo, xi1, xi2;
570 xo.buf = (char *)ehdr;
571 xo.size = bi->sz_unc;
572 xi2.buf = CONST_CAST(char *, bi); xi2.size = bi->sz_cpr + sizeof(*bi);
573 xi1.buf = CONST_CAST(char *, bi); xi1.size = sz_compressed;
574
575 // ehdr = Uncompress Ehdr and Phdrs
576 unpackExtent(&xi2, &xo, f_exp, 0); // never filtered?
577
578 #if defined(__x86_64) || defined(__aarch64__) //{
579 Elf64_Addr *const p_reloc = &elfaddr;
580 #endif //}
581 DPRINTF("upx_main1 .e_entry=%%p p_reloc=%%p *p_reloc=%%p PAGE_MASK=%%p\\n",
582 ehdr->e_entry, p_reloc, *p_reloc, PAGE_MASK);
583 Elf64_Phdr *phdr = (Elf64_Phdr *)(1+ ehdr);
584
585 // De-compress Ehdr again into actual position, then de-compress the rest.
586 Elf64_Addr entry = do_xmap(ehdr, &xi1, 0, av, f_exp, f_unf, p_reloc
587 #if defined(__powerpc64__) || defined(__aarch64__)
588 , PAGE_MASK
589 #endif
590 );
591 DPRINTF("upx_main2 entry=%%p *p_reloc=%%p\\n", entry, *p_reloc);
592 auxv_up(av, AT_ENTRY , entry);
593
594 { // Map PT_INTERP program interpreter
595 phdr = (Elf64_Phdr *)(1+ ehdr);
596 unsigned j;
597 for (j=0; j < ehdr->e_phnum; ++phdr, ++j) if (PT_INTERP==phdr->p_type) {
598 char const *const iname = *p_reloc + (char const *)phdr->p_vaddr;
599 int const fdi = open(iname, O_RDONLY, 0);
600 if (0 > fdi) {
601 err_exit(18);
602 }
603 if (MAX_ELF_HDR!=read(fdi, (void *)ehdr, MAX_ELF_HDR)) {
604 ERR_LAB
605 err_exit(19);
606 }
607 // We expect PT_INTERP to be ET_DYN at 0.
608 // Thus do_xmap will set *p_reloc = slide.
609 *p_reloc = 0; // kernel picks where PT_INTERP goes
610 entry = do_xmap(ehdr, 0, fdi, 0, 0, 0, p_reloc
611 #if defined(__powerpc64__) || defined(__aarch64__)
612 , PAGE_MASK
613 #endif
614 );
615 auxv_up(av, AT_BASE, *p_reloc); // musl
616 close(fdi);
617 }
618 }
619
620 return (void *)entry;
621 }
622
623 #if DEBUG //{
624
625 #if defined(__powerpc64__) //{
626 #define __NR_write 4
627
628 typedef unsigned long size_t;
629
630 #if 0 //{
631 static int
632 write(int fd, char const *ptr, size_t len)
633 {
634 register int sys asm("r0") = __NR_write;
635 register int a0 asm("r3") = fd;
636 register void const *a1 asm("r4") = ptr;
637 register size_t const a2 asm("r5") = len;
638 __asm__ __volatile__("sc"
639 : "=r"(a0)
640 : "r"(sys), "r"(a0), "r"(a1), "r"(a2)
641 : "r0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13"
642 );
643 return a0;
644 }
645 #else //}{
646 ssize_t
write(int fd,void const * ptr,size_t len)647 write(int fd, void const *ptr, size_t len)
648 {
649 register int sys asm("r0") = __NR_write;
650 register int a0 asm("r3") = fd;
651 register void const *a1 asm("r4") = ptr;
652 register size_t a2 asm("r5") = len;
653 __asm__ __volatile__("sc"
654 : "+r"(sys), "+r"(a0), "+r"(a1), "+r"(a2)
655 :
656 : "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13"
657 );
658 return a0;
659 }
660 #endif //}
661 #endif //}
662
663 static int
unsimal(unsigned x,char * ptr,int n)664 unsimal(unsigned x, char *ptr, int n)
665 {
666 unsigned m = 10;
667 while (10 <= (x / m)) m *= 10;
668 while (10 <= x) {
669 unsigned d = x / m;
670 x -= m * d;
671 m /= 10;
672 ptr[n++] = '0' + d;
673 }
674 ptr[n++] = '0' + x;
675 return n;
676 }
677
678 static int
decimal(int x,char * ptr,int n)679 decimal(int x, char *ptr, int n)
680 {
681 if (x < 0) {
682 x = -x;
683 ptr[n++] = '-';
684 }
685 return unsimal(x, ptr, n);
686 }
687
688 static int
heximal(unsigned long x,char * ptr,int n)689 heximal(unsigned long x, char *ptr, int n)
690 {
691 unsigned j = -1+ 2*sizeof(unsigned long);
692 unsigned long m = 0xful << (4 * j);
693 for (; j; --j, m >>= 4) { // omit leading 0 digits
694 if (m & x) break;
695 }
696 for (; m; --j, m >>= 4) {
697 unsigned d = 0xf & (x >> (4 * j));
698 ptr[n++] = ((10<=d) ? ('a' - 10) : '0') + d;
699 }
700 return n;
701 }
702
703 #define va_arg __builtin_va_arg
704 #define va_end __builtin_va_end
705 #define va_list __builtin_va_list
706 #define va_start __builtin_va_start
707
708 static int
dprintf(char const * fmt,...)709 dprintf(char const *fmt, ...)
710 {
711 int n= 0;
712 char const *literal = 0; // NULL
713 char buf[24]; // ~0ull == 18446744073709551615 ==> 20 chars
714 va_list va; va_start(va, fmt);
715 for (;;) {
716 char c = *fmt++;
717 if (!c) { // end of fmt
718 if (literal) {
719 goto finish;
720 }
721 break; // goto done
722 }
723 if ('%'!=c) {
724 if (!literal) {
725 literal = fmt; // 1 beyond start of literal
726 }
727 continue;
728 }
729 // '%' == c
730 if (literal) {
731 finish:
732 n += write(2, -1+ literal, fmt - literal);
733 literal = 0; // NULL
734 if (!c) { // fmt already ended
735 break; // goto done
736 }
737 }
738 switch (c= *fmt++) { // deficiency: does not handle _long_
739 default: { // un-implemented conversion
740 n+= write(2, -1+ fmt, 1);
741 } break;
742 case 0: { // fmt ends with "%\0" ==> ignore
743 goto done;
744 } break;
745 case 'u': {
746 n+= write(2, buf, unsimal(va_arg(va, unsigned), buf, 0));
747 } break;
748 case 'd': {
749 n+= write(2, buf, decimal(va_arg(va, int), buf, 0));
750 } break;
751 case 'p': {
752 buf[0] = '0';
753 buf[1] = 'x';
754 n+= write(2, buf, heximal((unsigned long)va_arg(va, void *), buf, 2));
755 } break;
756 case 'x': {
757 buf[0] = '0';
758 buf[1] = 'x';
759 n+= write(2, buf, heximal(va_arg(va, int), buf, 2));
760 } break;
761 } // 'switch'
762 }
763 done:
764 va_end(va);
765 return n;
766 }
767 #endif //}
768
769 /* vim:set ts=4 sw=4 et: */
770