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,8 +98,11 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i | ||
| 98 | 98 | ||
| 99 | static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) | 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 | #endif | 108 | #endif |
| @@ -129,9 +132,42 @@ do { \ | @@ -129,9 +132,42 @@ do { \ | ||
| 129 | _r->gpr[4] = (unsigned long)++pos; \ | 132 | _r->gpr[4] = (unsigned long)++pos; \ |
| 130 | for (; tmp != 0; pos++) \ | 133 | for (; tmp != 0; pos++) \ |
| 131 | tmp = *pos; \ | 134 | tmp = *pos; \ |
| 132 | - _r->gpr[5] = (unsigned long)pos; \ | 135 | + _r->gpr[5] = (unsigned long)pos; \ |
| 133 | } while (0) | 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 | static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) | 171 | static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) |
| 136 | { | 172 | { |
| 137 | _regs->msr = 1 << MSR_PR; /* Set user mode */ | 173 | _regs->msr = 1 << MSR_PR; /* Set user mode */ |
| @@ -225,7 +261,7 @@ struct exec | @@ -225,7 +261,7 @@ struct exec | ||
| 225 | #define INTERPRETER_AOUT 1 | 261 | #define INTERPRETER_AOUT 1 |
| 226 | #define INTERPRETER_ELF 2 | 262 | #define INTERPRETER_ELF 2 |
| 227 | 263 | ||
| 228 | -#define DLINFO_ITEMS 12 | 264 | +#define DLINFO_ITEMS 11 |
| 229 | 265 | ||
| 230 | #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) | 266 | #define put_user(x,ptr) (void)(*(ptr) = (typeof(*ptr))(x)) |
| 231 | #define get_user(ptr) (typeof(*ptr))(*(ptr)) | 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,15 +595,51 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | ||
| 559 | unsigned long interp_load_addr, int ibcs, | 595 | unsigned long interp_load_addr, int ibcs, |
| 560 | struct image_info *info) | 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 | sp = (unsigned int *) (~15UL & (unsigned long) p); | 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 | sp -= envc+1; | 643 | sp -= envc+1; |
| 572 | envp = sp; | 644 | envp = sp; |
| 573 | sp -= argc+1; | 645 | sp -= argc+1; |
| @@ -576,25 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | @@ -576,25 +648,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc, | ||
| 576 | put_user(tswapl((target_ulong)envp),--sp); | 648 | put_user(tswapl((target_ulong)envp),--sp); |
| 577 | put_user(tswapl((target_ulong)argv),--sp); | 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 | put_user(tswapl(argc),--sp); | 651 | put_user(tswapl(argc),--sp); |
| 599 | info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); | 652 | info->arg_start = (unsigned int)((unsigned long)p & 0xffffffff); |
| 600 | while (argc-->0) { | 653 | while (argc-->0) { |