Commit f515528907764d1fb1fab2e68a8be25e15b3c096
1 parent
b453b70b
aligned stack on 16 byte boundary - PPC target fixes - SPARC target fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@491 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
84 additions
and
31 deletions
linux-user/elfload.c
| ... | ... | @@ -98,8 +98,11 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i |
| 98 | 98 | |
| 99 | 99 | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) |
| 100 | 100 | { |
| 101 | - regs->u_regs[0] = infop->entry; | |
| 102 | - regs->u_regs[1] = infop->start_stack; | |
| 101 | + regs->psr = 0; | |
| 102 | + regs->pc = infop->entry; | |
| 103 | + regs->npc = regs->pc + 4; | |
| 104 | + regs->y = 0; | |
| 105 | + regs->u_regs[14] = infop->start_stack - 16 * 4; | |
| 103 | 106 | } |
| 104 | 107 | |
| 105 | 108 | #endif |
| ... | ... | @@ -129,9 +132,42 @@ do { \ |
| 129 | 132 | _r->gpr[4] = (unsigned long)++pos; \ |
| 130 | 133 | for (; tmp != 0; pos++) \ |
| 131 | 134 | tmp = *pos; \ |
| 132 | - _r->gpr[5] = (unsigned long)pos; \ | |
| 135 | + _r->gpr[5] = (unsigned long)pos; \ | |
| 133 | 136 | } while (0) |
| 134 | 137 | |
| 138 | +/* | |
| 139 | + * We need to put in some extra aux table entries to tell glibc what | |
| 140 | + * the cache block size is, so it can use the dcbz instruction safely. | |
| 141 | + */ | |
| 142 | +#define AT_DCACHEBSIZE 19 | |
| 143 | +#define AT_ICACHEBSIZE 20 | |
| 144 | +#define AT_UCACHEBSIZE 21 | |
| 145 | +/* A special ignored type value for PPC, for glibc compatibility. */ | |
| 146 | +#define AT_IGNOREPPC 22 | |
| 147 | +/* | |
| 148 | + * The requirements here are: | |
| 149 | + * - keep the final alignment of sp (sp & 0xf) | |
| 150 | + * - make sure the 32-bit value at the first 16 byte aligned position of | |
| 151 | + * AUXV is greater than 16 for glibc compatibility. | |
| 152 | + * AT_IGNOREPPC is used for that. | |
| 153 | + * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC, | |
| 154 | + * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. | |
| 155 | + */ | |
| 156 | +#define DLINFO_ARCH_ITEMS 3 | |
| 157 | +#define ARCH_DLINFO \ | |
| 158 | +do { \ | |
| 159 | + sp -= DLINFO_ARCH_ITEMS * 2; \ | |
| 160 | + NEW_AUX_ENT(0, AT_DCACHEBSIZE, 0x20); \ | |
| 161 | + NEW_AUX_ENT(1, AT_ICACHEBSIZE, 0x20); \ | |
| 162 | + NEW_AUX_ENT(2, AT_UCACHEBSIZE, 0); \ | |
| 163 | + /* \ | |
| 164 | + * Now handle glibc compatibility. \ | |
| 165 | + */ \ | |
| 166 | + sp -= 2*2; \ | |
| 167 | + NEW_AUX_ENT(0, AT_IGNOREPPC, AT_IGNOREPPC); \ | |
| 168 | + NEW_AUX_ENT(1, AT_IGNOREPPC, AT_IGNOREPPC); \ | |
| 169 | + } while (0) | |
| 170 | + | |
| 135 | 171 | static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) |
| 136 | 172 | { |
| 137 | 173 | _regs->msr = 1 << MSR_PR; /* Set user mode */ |
| ... | ... | @@ -225,7 +261,7 @@ struct exec |
| 225 | 261 | #define INTERPRETER_AOUT 1 |
| 226 | 262 | #define INTERPRETER_ELF 2 |
| 227 | 263 | |
| 228 | -#define DLINFO_ITEMS 12 | |
| 264 | +#define DLINFO_ITEMS 11 | |
| 229 | 265 | |
| 230 | 266 | #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) |
| 231 | 267 | #define get_user(ptr) (typeof(*ptr))(*(ptr)) |
| ... | ... | @@ -559,15 +595,51 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, |
| 559 | 595 | unsigned long interp_load_addr, int ibcs, |
| 560 | 596 | struct image_info *info) |
| 561 | 597 | { |
| 562 | - target_ulong *argv, *envp, *dlinfo; | |
| 563 | - target_ulong *sp; | |
| 564 | - | |
| 565 | - /* | |
| 566 | - * Force 16 byte alignment here for generality. | |
| 567 | - */ | |
| 598 | + target_ulong *argv, *envp; | |
| 599 | + target_ulong *sp, *csp; | |
| 600 | + | |
| 601 | + /* | |
| 602 | + * Force 16 byte _final_ alignment here for generality. | |
| 603 | + */ | |
| 568 | 604 | sp = (unsigned int *) (~15UL & (unsigned long) p); |
| 569 | - sp -= DLINFO_ITEMS*2; | |
| 570 | - dlinfo = sp; | |
| 605 | + csp = sp; | |
| 606 | + csp -= (DLINFO_ITEMS + 1) * 2; | |
| 607 | +#ifdef DLINFO_ARCH_ITEMS | |
| 608 | + csp -= DLINFO_ARCH_ITEMS*2; | |
| 609 | +#endif | |
| 610 | + csp -= envc+1; | |
| 611 | + csp -= argc+1; | |
| 612 | + csp -= (!ibcs ? 3 : 1); /* argc itself */ | |
| 613 | + if ((unsigned long)csp & 15UL) | |
| 614 | + sp -= ((unsigned long)csp & 15UL) / sizeof(*sp); | |
| 615 | + | |
| 616 | +#define NEW_AUX_ENT(nr, id, val) \ | |
| 617 | + put_user (tswapl(id), sp + (nr * 2)); \ | |
| 618 | + put_user (tswapl(val), sp + (nr * 2 + 1)) | |
| 619 | + sp -= 2; | |
| 620 | + NEW_AUX_ENT (0, AT_NULL, 0); | |
| 621 | + | |
| 622 | + sp -= DLINFO_ITEMS*2; | |
| 623 | + NEW_AUX_ENT( 0, AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); | |
| 624 | + NEW_AUX_ENT( 1, AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); | |
| 625 | + NEW_AUX_ENT( 2, AT_PHNUM, (target_ulong)(exec->e_phnum)); | |
| 626 | + NEW_AUX_ENT( 3, AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); | |
| 627 | + NEW_AUX_ENT( 4, AT_BASE, (target_ulong)(interp_load_addr)); | |
| 628 | + NEW_AUX_ENT( 5, AT_FLAGS, (target_ulong)0); | |
| 629 | + NEW_AUX_ENT( 6, AT_ENTRY, load_bias + exec->e_entry); | |
| 630 | + NEW_AUX_ENT( 7, AT_UID, (target_ulong) getuid()); | |
| 631 | + NEW_AUX_ENT( 8, AT_EUID, (target_ulong) geteuid()); | |
| 632 | + NEW_AUX_ENT( 9, AT_GID, (target_ulong) getgid()); | |
| 633 | + NEW_AUX_ENT(11, AT_EGID, (target_ulong) getegid()); | |
| 634 | +#ifdef ARCH_DLINFO | |
| 635 | + /* | |
| 636 | + * ARCH_DLINFO must come last so platform specific code can enforce | |
| 637 | + * special alignment requirements on the AUXV if necessary (eg. PPC). | |
| 638 | + */ | |
| 639 | + ARCH_DLINFO; | |
| 640 | +#endif | |
| 641 | +#undef NEW_AUX_ENT | |
| 642 | + | |
| 571 | 643 | sp -= envc+1; |
| 572 | 644 | envp = sp; |
| 573 | 645 | sp -= argc+1; |
| ... | ... | @@ -576,25 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, |
| 576 | 648 | put_user(tswapl((target_ulong)envp),--sp); |
| 577 | 649 | put_user(tswapl((target_ulong)argv),--sp); |
| 578 | 650 | } |
| 579 | - | |
| 580 | -#define NEW_AUX_ENT(id, val) \ | |
| 581 | - put_user (tswapl(id), dlinfo++); \ | |
| 582 | - put_user (tswapl(val), dlinfo++) | |
| 583 | - | |
| 584 | - NEW_AUX_ENT (AT_PHDR, (target_ulong)(load_addr + exec->e_phoff)); | |
| 585 | - NEW_AUX_ENT (AT_PHENT, (target_ulong)(sizeof (struct elf_phdr))); | |
| 586 | - NEW_AUX_ENT (AT_PHNUM, (target_ulong)(exec->e_phnum)); | |
| 587 | - NEW_AUX_ENT (AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE)); | |
| 588 | - NEW_AUX_ENT (AT_BASE, (target_ulong)(interp_load_addr)); | |
| 589 | - NEW_AUX_ENT (AT_FLAGS, (target_ulong)0); | |
| 590 | - NEW_AUX_ENT (AT_ENTRY, load_bias + exec->e_entry); | |
| 591 | - NEW_AUX_ENT (AT_UID, (target_ulong) getuid()); | |
| 592 | - NEW_AUX_ENT (AT_EUID, (target_ulong) geteuid()); | |
| 593 | - NEW_AUX_ENT (AT_GID, (target_ulong) getgid()); | |
| 594 | - NEW_AUX_ENT (AT_EGID, (target_ulong) getegid()); | |
| 595 | - NEW_AUX_ENT (AT_NULL, 0); | |
| 596 | -#undef NEW_AUX_ENT | |
| 597 | - | |
| 598 | 651 | put_user(tswapl(argc),--sp); |
| 599 | 652 | info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); |
| 600 | 653 | while (argc-->0) { | ... | ... |