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) { | ... | ... |