2 * Written 2000,2002 by Andi Kleen.
4 * Loosely based on the sparc64 and IA64 32bit emulation loaders.
5 * This tricks binfmt_elf.c into loading 32bit binaries using lots
6 * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
9 #include <linux/types.h>
10 #include <linux/stddef.h>
11 #include <linux/rwsem.h>
12 #include <linux/sched.h>
13 #include <linux/compat.h>
14 #include <linux/string.h>
15 #include <linux/binfmts.h>
17 #include <linux/security.h>
18 #include <linux/elfcore-compat.h>
20 #include <asm/segment.h>
21 #include <asm/ptrace.h>
22 #include <asm/processor.h>
23 #include <asm/user32.h>
24 #include <asm/sigcontext32.h>
25 #include <asm/fpu32.h>
27 #include <asm/uaccess.h>
29 #include <asm/vsyscall32.h>
33 #define ELF_CLASS ELFCLASS32
34 #define ELF_ARCH EM_386
40 #define elfhdr elf32_hdr
41 #define elf_phdr elf32_phdr
42 #define elf_note elf32_note
43 #define elf_addr_t Elf32_Off
45 #define ELF_NAME "elf/i386"
48 #define AT_SYSINFO_EHDR 33
50 int sysctl_vsyscall32
= 1;
53 #define ARCH_DLINFO do { \
54 if (sysctl_vsyscall32) { \
55 current->mm->context.vdso = (void *)VSYSCALL32_BASE; \
56 NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
57 NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE); \
63 #define IA32_EMULATOR 1
65 #undef ELF_ET_DYN_BASE
67 #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000)
69 #define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
72 ({ __u32 seg; asm("movl %%" __stringify(x) ",%0" : "=r"(seg)); seg; })
74 /* Assumes current==process to be dumped */
75 #undef ELF_CORE_COPY_REGS
76 #define ELF_CORE_COPY_REGS(pr_reg, regs) \
77 pr_reg[0] = regs->rbx; \
78 pr_reg[1] = regs->rcx; \
79 pr_reg[2] = regs->rdx; \
80 pr_reg[3] = regs->rsi; \
81 pr_reg[4] = regs->rdi; \
82 pr_reg[5] = regs->rbp; \
83 pr_reg[6] = regs->rax; \
84 pr_reg[7] = _GET_SEG(ds); \
85 pr_reg[8] = _GET_SEG(es); \
86 pr_reg[9] = _GET_SEG(fs); \
87 pr_reg[10] = _GET_SEG(gs); \
88 pr_reg[11] = regs->orig_rax; \
89 pr_reg[12] = regs->rip; \
90 pr_reg[13] = regs->cs; \
91 pr_reg[14] = regs->eflags; \
92 pr_reg[15] = regs->rsp; \
93 pr_reg[16] = regs->ss;
96 #define elf_prstatus compat_elf_prstatus
97 #define elf_prpsinfo compat_elf_prpsinfo
98 #define elf_fpregset_t struct user_i387_ia32_struct
99 #define elf_fpxregset_t struct user32_fxsr_struct
102 #undef elf_read_implies_exec
103 #define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X)
105 #define elf_core_copy_regs elf32_core_copy_regs
106 static inline void elf32_core_copy_regs(compat_elf_gregset_t
*elfregs
,
107 struct pt_regs
*regs
)
109 ELF_CORE_COPY_REGS((&elfregs
->ebx
), regs
)
112 #define elf_core_copy_task_regs elf32_core_copy_task_regs
113 static inline int elf32_core_copy_task_regs(struct task_struct
*t
,
114 compat_elf_gregset_t
* elfregs
)
116 struct pt_regs
*pp
= task_pt_regs(t
);
117 ELF_CORE_COPY_REGS((&elfregs
->ebx
), pp
);
118 /* fix wrong segments */
119 elfregs
->ds
= t
->thread
.ds
;
120 elfregs
->fs
= t
->thread
.fsindex
;
121 elfregs
->gs
= t
->thread
.gsindex
;
122 elfregs
->es
= t
->thread
.es
;
126 #define elf_core_copy_task_fpregs elf32_core_copy_task_fpregs
128 elf32_core_copy_task_fpregs(struct task_struct
*tsk
, struct pt_regs
*regs
,
131 struct _fpstate_ia32
*fpstate
= (void*)fpu
;
132 mm_segment_t oldfs
= get_fs();
134 if (!tsk_used_math(tsk
))
137 regs
= task_pt_regs(tsk
);
141 save_i387_ia32(tsk
, fpstate
, regs
, 1);
142 /* Correct for i386 bug. It puts the fop into the upper 16bits of
143 the tag word (like FXSAVE), not into the fcs*/
144 fpstate
->cssel
|= fpstate
->tag
& 0xffff0000;
149 #define ELF_CORE_COPY_XFPREGS 1
150 #define ELF_CORE_XFPREG_TYPE NT_PRXFPREG
151 #define elf_core_copy_task_xfpregs elf32_core_copy_task_xfpregs
153 elf32_core_copy_task_xfpregs(struct task_struct
*t
, elf_fpxregset_t
*xfpu
)
155 struct pt_regs
*regs
= task_pt_regs(t
);
156 if (!tsk_used_math(t
))
160 memcpy(xfpu
, &t
->thread
.i387
.fxsave
, sizeof(elf_fpxregset_t
));
161 xfpu
->fcs
= regs
->cs
;
162 xfpu
->fos
= t
->thread
.ds
; /* right? */
166 #undef elf_check_arch
167 #define elf_check_arch(x) \
168 ((x)->e_machine == EM_386)
170 extern int force_personality32
;
172 #undef ELF_EXEC_PAGESIZE
175 #undef SET_PERSONALITY
176 #define ELF_EXEC_PAGESIZE PAGE_SIZE
177 #define ELF_HWCAP (boot_cpu_data.x86_capability[0])
178 #define ELF_PLATFORM ("i686")
179 #define SET_PERSONALITY(ex, ibcs2) \
181 unsigned long new_flags = 0; \
182 if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
183 new_flags = _TIF_IA32; \
184 if ((current_thread_info()->flags & _TIF_IA32) \
186 set_thread_flag(TIF_ABI_PENDING); \
188 clear_thread_flag(TIF_ABI_PENDING); \
189 /* XXX This overwrites the user set personality */ \
190 current->personality |= force_personality32; \
193 /* Override some function names */
194 #define elf_format elf32_format
196 #define init_elf_binfmt init_elf32_binfmt
197 #define exit_elf_binfmt exit_elf32_binfmt
199 #define load_elf_binary load_elf32_binary
202 #define ELF_PLAT_INIT(r, load_addr) elf32_init(r)
205 #define start_thread(regs,new_rip,new_rsp) do { \
206 asm volatile("movl %0,%%fs" :: "r" (0)); \
207 asm volatile("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
209 (regs)->rip = (new_rip); \
210 (regs)->rsp = (new_rsp); \
211 (regs)->eflags = 0x200; \
212 (regs)->cs = __USER32_CS; \
213 (regs)->ss = __USER32_DS; \
218 #include <linux/module.h>
220 MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries.");
221 MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
223 #undef MODULE_DESCRIPTION
226 static void elf32_init(struct pt_regs
*);
228 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
229 #define arch_setup_additional_pages syscall32_setup_pages
230 extern int syscall32_setup_pages(struct linux_binprm
*, int exstack
);
232 #include "../../../fs/binfmt_elf.c"
234 static void elf32_init(struct pt_regs
*regs
)
236 struct task_struct
*me
= current
;
244 regs
->r8
= regs
->r9
= regs
->r10
= regs
->r11
= regs
->r12
=
245 regs
->r13
= regs
->r14
= regs
->r15
= 0;
248 me
->thread
.fsindex
= 0;
249 me
->thread
.gsindex
= 0;
250 me
->thread
.ds
= __USER_DS
;
251 me
->thread
.es
= __USER_DS
;
255 /* Register vsyscall32 into the ABI table */
256 #include <linux/sysctl.h>
258 static ctl_table abi_table2
[] = {
260 .procname
= "vsyscall32",
261 .data
= &sysctl_vsyscall32
,
262 .maxlen
= sizeof(int),
264 .proc_handler
= proc_dointvec
269 static ctl_table abi_root_table2
[] = {
279 static __init
int ia32_binfmt_init(void)
281 register_sysctl_table(abi_root_table2
);
284 __initcall(ia32_binfmt_init
);