Revision 53a5960a linux-user/elfload.c
b/linux-user/elfload.c | ||
---|---|---|
97 | 97 |
|
98 | 98 |
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
99 | 99 |
{ |
100 |
target_long *stack = (void *)infop->start_stack;
|
|
100 |
target_long stack = infop->start_stack;
|
|
101 | 101 |
memset(regs, 0, sizeof(*regs)); |
102 | 102 |
regs->ARM_cpsr = 0x10; |
103 | 103 |
if (infop->entry & 1) |
104 | 104 |
regs->ARM_cpsr |= CPSR_T; |
105 | 105 |
regs->ARM_pc = infop->entry & 0xfffffffe; |
106 | 106 |
regs->ARM_sp = infop->start_stack; |
107 |
regs->ARM_r2 = tswapl(stack[2]); /* envp */
|
|
108 |
regs->ARM_r1 = tswapl(stack[1]); /* argv */
|
|
107 |
regs->ARM_r2 = tgetl(stack + 8); /* envp */
|
|
108 |
regs->ARM_r1 = tgetl(stack + 4); /* envp */
|
|
109 | 109 |
/* XXX: it seems that r0 is zeroed after ! */ |
110 |
// regs->ARM_r0 = tswapl(stack[0]); /* argc */
|
|
110 |
// regs->ARM_r0 = tgetl(stack); /* argc */
|
|
111 | 111 |
} |
112 | 112 |
|
113 | 113 |
#define USE_ELF_CORE_DUMP |
... | ... | |
202 | 202 |
_r->gpr[3] = bprm->argc; \ |
203 | 203 |
_r->gpr[4] = (unsigned long)++pos; \ |
204 | 204 |
for (; tmp != 0; pos++) \ |
205 |
tmp = *pos; \
|
|
205 |
tmp = ldl(pos); \
|
|
206 | 206 |
_r->gpr[5] = (unsigned long)pos; \ |
207 | 207 |
} while (0) |
208 | 208 |
|
... | ... | |
297 | 297 |
*/ |
298 | 298 |
struct linux_binprm { |
299 | 299 |
char buf[128]; |
300 |
unsigned long page[MAX_ARG_PAGES];
|
|
300 |
void *page[MAX_ARG_PAGES];
|
|
301 | 301 |
unsigned long p; |
302 | 302 |
int sh_bang; |
303 | 303 |
int fd; |
... | ... | |
427 | 427 |
} |
428 | 428 |
#endif |
429 | 429 |
|
430 |
static void * get_free_page(void) |
|
431 |
{ |
|
432 |
void * retval; |
|
433 |
|
|
434 |
/* User-space version of kernel get_free_page. Returns a page-aligned |
|
435 |
* page-sized chunk of memory. |
|
436 |
*/ |
|
437 |
retval = (void *)target_mmap(0, qemu_host_page_size, PROT_READ|PROT_WRITE, |
|
438 |
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
|
439 |
|
|
440 |
if((long)retval == -1) { |
|
441 |
perror("get_free_page"); |
|
442 |
exit(-1); |
|
443 |
} |
|
444 |
else { |
|
445 |
return(retval); |
|
446 |
} |
|
447 |
} |
|
448 |
|
|
449 |
static void free_page(void * pageaddr) |
|
450 |
{ |
|
451 |
target_munmap((unsigned long)pageaddr, qemu_host_page_size); |
|
452 |
} |
|
453 |
|
|
454 | 430 |
/* |
455 | 431 |
* 'copy_string()' copies argument/envelope strings from user |
456 | 432 |
* memory to free pages in kernel mem. These are in a format ready |
457 | 433 |
* to be put directly into the top of new user memory. |
458 | 434 |
* |
459 | 435 |
*/ |
460 |
static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
|
|
436 |
static unsigned long copy_strings(int argc,char ** argv, void **page,
|
|
461 | 437 |
unsigned long p) |
462 | 438 |
{ |
463 | 439 |
char *tmp, *tmp1, *pag = NULL; |
... | ... | |
482 | 458 |
--p; --tmp; --len; |
483 | 459 |
if (--offset < 0) { |
484 | 460 |
offset = p % TARGET_PAGE_SIZE; |
485 |
pag = (char *) page[p/TARGET_PAGE_SIZE];
|
|
461 |
pag = (char *)page[p/TARGET_PAGE_SIZE]; |
|
486 | 462 |
if (!pag) { |
487 |
pag = (char *)get_free_page();
|
|
488 |
page[p/TARGET_PAGE_SIZE] = (unsigned long)pag;
|
|
463 |
pag = (char *)malloc(TARGET_PAGE_SIZE);
|
|
464 |
page[p/TARGET_PAGE_SIZE] = pag; |
|
489 | 465 |
if (!pag) |
490 | 466 |
return 0; |
491 | 467 |
} |
... | ... | |
591 | 567 |
} |
592 | 568 |
} |
593 | 569 |
|
594 |
unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm,
|
|
595 |
struct image_info * info)
|
|
570 |
static inline void memcpy_to_target(target_ulong dest, const void *src,
|
|
571 |
unsigned long len)
|
|
596 | 572 |
{ |
597 |
unsigned long stack_base, size, error; |
|
573 |
void *host_ptr; |
|
574 |
|
|
575 |
host_ptr = lock_user(dest, len, 0); |
|
576 |
memcpy(host_ptr, src, len); |
|
577 |
unlock_user(host_ptr, dest, 1); |
|
578 |
} |
|
579 |
|
|
580 |
unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm, |
|
581 |
struct image_info * info) |
|
582 |
{ |
|
583 |
target_ulong stack_base, size, error; |
|
598 | 584 |
int i; |
599 | 585 |
|
600 | 586 |
/* Create enough stack to hold everything. If we don't use |
... | ... | |
627 | 613 |
if (bprm->page[i]) { |
628 | 614 |
info->rss++; |
629 | 615 |
|
630 |
memcpy((void *)stack_base, (void *)bprm->page[i], TARGET_PAGE_SIZE);
|
|
631 |
free_page((void *)bprm->page[i]);
|
|
616 |
memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
|
|
617 |
free(bprm->page[i]);
|
|
632 | 618 |
} |
633 |
stack_base += TARGET_PAGE_SIZE;
|
|
619 |
stack_base += TARGET_PAGE_SIZE;
|
|
634 | 620 |
} |
635 | 621 |
return p; |
636 | 622 |
} |
... | ... | |
657 | 643 |
static void padzero(unsigned long elf_bss) |
658 | 644 |
{ |
659 | 645 |
unsigned long nbyte; |
660 |
char * fpnt; |
|
661 | 646 |
|
662 | 647 |
/* XXX: this is really a hack : if the real host page size is |
663 | 648 |
smaller than the target page size, some pages after the end |
... | ... | |
679 | 664 |
nbyte = elf_bss & (qemu_host_page_size-1); |
680 | 665 |
if (nbyte) { |
681 | 666 |
nbyte = qemu_host_page_size - nbyte; |
682 |
fpnt = (char *) elf_bss; |
|
683 | 667 |
do { |
684 |
*fpnt++ = 0; |
|
668 |
tput8(elf_bss, 0); |
|
669 |
elf_bss++; |
|
685 | 670 |
} while (--nbyte); |
686 | 671 |
} |
687 | 672 |
} |
688 | 673 |
|
689 |
static unsigned int * create_elf_tables(char *p, int argc, int envc, |
|
690 |
struct elfhdr * exec, |
|
691 |
unsigned long load_addr, |
|
692 |
unsigned long load_bias, |
|
693 |
unsigned long interp_load_addr, int ibcs, |
|
694 |
struct image_info *info) |
|
674 |
|
|
675 |
static unsigned long create_elf_tables(target_ulong p, int argc, int envc, |
|
676 |
struct elfhdr * exec, |
|
677 |
unsigned long load_addr, |
|
678 |
unsigned long load_bias, |
|
679 |
unsigned long interp_load_addr, int ibcs, |
|
680 |
struct image_info *info) |
|
695 | 681 |
{ |
696 |
target_ulong *argv, *envp; |
|
697 |
target_ulong *sp, *csp; |
|
698 |
target_ulong *u_platform; |
|
682 |
target_ulong argv, envp; |
|
683 |
target_ulong sp; |
|
684 |
int size; |
|
685 |
target_ulong u_platform; |
|
699 | 686 |
const char *k_platform; |
700 |
int v;
|
|
687 |
const int n = sizeof(target_ulong);
|
|
701 | 688 |
|
702 |
/* |
|
703 |
* Force 16 byte _final_ alignment here for generality. |
|
704 |
*/ |
|
705 |
sp = (unsigned int *) (~15UL & (unsigned long) p); |
|
706 |
u_platform = NULL; |
|
689 |
sp = p; |
|
690 |
u_platform = 0; |
|
707 | 691 |
k_platform = ELF_PLATFORM; |
708 | 692 |
if (k_platform) { |
709 | 693 |
size_t len = strlen(k_platform) + 1; |
710 |
sp -= (len + sizeof(target_ulong) - 1) / sizeof(target_ulong);
|
|
711 |
u_platform = (target_ulong *)sp;
|
|
712 |
__copy_to_user(u_platform, k_platform, len);
|
|
694 |
sp -= (len + n - 1) & ~(n - 1);
|
|
695 |
u_platform = sp; |
|
696 |
memcpy_to_target(sp, k_platform, len);
|
|
713 | 697 |
} |
714 |
csp = sp; |
|
715 |
csp -= (DLINFO_ITEMS + 1) * 2; |
|
698 |
/* |
|
699 |
* Force 16 byte _final_ alignment here for generality. |
|
700 |
*/ |
|
701 |
sp = sp &~ (target_ulong)15; |
|
702 |
size = (DLINFO_ITEMS + 1) * 2; |
|
716 | 703 |
if (k_platform) |
717 |
csp -= 2;
|
|
704 |
size += 2;
|
|
718 | 705 |
#ifdef DLINFO_ARCH_ITEMS |
719 |
csp -= DLINFO_ARCH_ITEMS*2;
|
|
706 |
size += DLINFO_ARCH_ITEMS * 2;
|
|
720 | 707 |
#endif |
721 |
csp -= envc+1;
|
|
722 |
csp -= argc+1;
|
|
723 |
csp -= (!ibcs ? 3 : 1); /* argc itself */
|
|
724 |
if ((unsigned long)csp & 15UL)
|
|
725 |
sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
|
|
708 |
size += envc + argc + 2;
|
|
709 |
size += (!ibcs ? 3 : 1); /* argc itself */
|
|
710 |
size *= n;
|
|
711 |
if (size & 15)
|
|
712 |
sp -= 16 - (size & 15);
|
|
726 | 713 |
|
727 |
#define NEW_AUX_ENT(id, val) \ |
|
728 |
sp -= 2; \
|
|
729 |
put_user (id, sp); \
|
|
730 |
put_user (val, sp + 1)
|
|
714 |
#define NEW_AUX_ENT(id, val) do { \
|
|
715 |
sp -= n; tputl(sp, val); \
|
|
716 |
sp -= n; tputl(sp, id); \
|
|
717 |
} while(0)
|
|
731 | 718 |
NEW_AUX_ENT (AT_NULL, 0); |
732 | 719 |
|
733 | 720 |
/* There must be exactly DLINFO_ITEMS entries here. */ |
... | ... | |
744 | 731 |
NEW_AUX_ENT(AT_EGID, (target_ulong) getegid()); |
745 | 732 |
NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP); |
746 | 733 |
if (k_platform) |
747 |
NEW_AUX_ENT(AT_PLATFORM, (target_ulong) u_platform);
|
|
734 |
NEW_AUX_ENT(AT_PLATFORM, u_platform); |
|
748 | 735 |
#ifdef ARCH_DLINFO |
749 | 736 |
/* |
750 | 737 |
* ARCH_DLINFO must come last so platform specific code can enforce |
... | ... | |
754 | 741 |
#endif |
755 | 742 |
#undef NEW_AUX_ENT |
756 | 743 |
|
757 |
sp -= envc+1;
|
|
744 |
sp -= (envc + 1) * n;
|
|
758 | 745 |
envp = sp; |
759 |
sp -= argc+1;
|
|
746 |
sp -= (argc + 1) * n;
|
|
760 | 747 |
argv = sp; |
761 | 748 |
if (!ibcs) { |
762 |
put_user((target_ulong)envp,--sp);
|
|
763 |
put_user((target_ulong)argv,--sp);
|
|
749 |
sp -= n; tputl(sp, envp);
|
|
750 |
sp -= n; tputl(sp, argv);
|
|
764 | 751 |
} |
765 |
put_user(argc,--sp);
|
|
766 |
info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
|
752 |
sp -= n; tputl(sp, argc);
|
|
753 |
info->arg_start = p;
|
|
767 | 754 |
while (argc-->0) { |
768 |
put_user((target_ulong)p,argv++); |
|
769 |
do { |
|
770 |
get_user(v, p); |
|
771 |
p++; |
|
772 |
} while (v != 0); |
|
755 |
tputl(argv, p); argv += n; |
|
756 |
p += target_strlen(p) + 1; |
|
773 | 757 |
} |
774 |
put_user(0,argv);
|
|
775 |
info->arg_end = info->env_start = (unsigned int)((unsigned long)p & 0xffffffff);
|
|
758 |
tputl(argv, 0);
|
|
759 |
info->arg_end = info->env_start = p;
|
|
776 | 760 |
while (envc-->0) { |
777 |
put_user((target_ulong)p,envp++); |
|
778 |
do { |
|
779 |
get_user(v, p); |
|
780 |
p++; |
|
781 |
} while (v != 0); |
|
761 |
tputl(envp, p); envp += n; |
|
762 |
p += target_strlen(p) + 1; |
|
782 | 763 |
} |
783 |
put_user(0,envp);
|
|
784 |
info->env_end = (unsigned int)((unsigned long)p & 0xffffffff);
|
|
764 |
tputl(envp, 0);
|
|
765 |
info->env_end = p;
|
|
785 | 766 |
return sp; |
786 | 767 |
} |
787 | 768 |
|
788 | 769 |
|
789 |
|
|
790 | 770 |
static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, |
791 | 771 |
int interpreter_fd, |
792 | 772 |
unsigned long *interp_load_addr) |
... | ... | |
1335 | 1315 |
#ifdef LOW_ELF_STACK |
1336 | 1316 |
info->start_stack = bprm->p = elf_stack - 4; |
1337 | 1317 |
#endif |
1338 |
bprm->p = (unsigned long) |
|
1339 |
create_elf_tables((char *)bprm->p, |
|
1318 |
bprm->p = create_elf_tables(bprm->p, |
|
1340 | 1319 |
bprm->argc, |
1341 | 1320 |
bprm->envc, |
1342 | 1321 |
&elf_ex, |
... | ... | |
1432 | 1411 |
if(retval>=0) { |
1433 | 1412 |
retval = load_elf_binary(&bprm,regs,infop); |
1434 | 1413 |
} |
1414 |
|
|
1435 | 1415 |
if(retval>=0) { |
1436 | 1416 |
/* success. Initialize important registers */ |
1437 | 1417 |
init_thread(regs, infop); |
... | ... | |
1440 | 1420 |
|
1441 | 1421 |
/* Something went wrong, return the inode and free the argument pages*/ |
1442 | 1422 |
for (i=0 ; i<MAX_ARG_PAGES ; i++) { |
1443 |
free_page((void *)bprm.page[i]);
|
|
1423 |
free(bprm.page[i]);
|
|
1444 | 1424 |
} |
1445 | 1425 |
return(retval); |
1446 | 1426 |
} |
Also available in: Unified diff