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