1 /* $NetBSD: linux_exec_aout.c,v 1.65 2008/04/28 20:23:43 martin Exp $ */
4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas, Frank van der Linden and Eric Haszlakiewicz.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * based on exec_aout.c, sunos_exec.c and svr4_exec.c
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: linux_exec_aout.c,v 1.65 2008/04/28 20:23:43 martin Exp $");
40 #include "opt_execfmt.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/namei.h>
49 #include <sys/vnode.h>
50 #include <sys/mount.h>
54 #include <sys/syscallargs.h>
57 #include <machine/reg.h>
59 #include <compat/linux/common/linux_types.h>
60 #include <compat/linux/common/linux_signal.h>
61 #include <compat/linux/common/linux_util.h>
62 #include <compat/linux/common/linux_exec.h>
63 #include <compat/linux/common/linux_machdep.h>
65 #include <compat/linux/linux_syscallargs.h>
66 #include <compat/linux/linux_syscall.h>
68 int linux_aout_copyargs(struct lwp
*, struct exec_package
*,
69 struct ps_strings
*, char **, void *);
71 static int exec_linux_aout_prep_zmagic(struct lwp
*,
72 struct exec_package
*);
73 static int exec_linux_aout_prep_nmagic(struct lwp
*,
74 struct exec_package
*);
75 static int exec_linux_aout_prep_omagic(struct lwp
*,
76 struct exec_package
*);
77 static int exec_linux_aout_prep_qmagic(struct lwp
*,
78 struct exec_package
*);
81 linux_aout_copyargs(struct lwp
*l
, struct exec_package
*pack
,
82 struct ps_strings
*arginfo
, char **stackp
, void *argp
)
84 char **cpp
= (char **)*stackp
;
85 char **stk
= (char **)*stackp
;
89 int argc
= arginfo
->ps_nargvstr
;
90 int envc
= arginfo
->ps_nenvstr
;
93 if ((error
= copyout(&argc
, cpp
++, sizeof(argc
))) != 0)
96 /* leave room for envp and argv */
98 if ((error
= copyout(&cpp
, &stk
[1], sizeof (cpp
))) != 0)
101 dp
= (char *) (cpp
+ argc
+ envc
+ 2);
104 /* XXX don't copy them out, remap them! */
105 arginfo
->ps_argvstr
= cpp
; /* remember location of argv for later */
107 for (; --argc
>= 0; sp
+= len
, dp
+= len
)
108 if ((error
= copyout(&dp
, cpp
++, sizeof(dp
))) != 0 ||
109 (error
= copyoutstr(sp
, dp
, ARG_MAX
, &len
)) != 0)
112 if ((error
= copyout(&nullp
, cpp
++, sizeof(nullp
))) != 0)
115 if ((error
= copyout(&cpp
, &stk
[2], sizeof (cpp
))) != 0)
118 arginfo
->ps_envstr
= cpp
; /* remember location of envp for later */
120 for (; --envc
>= 0; sp
+= len
, dp
+= len
)
121 if ((error
= copyout(&dp
, cpp
++, sizeof(dp
))) != 0 ||
122 (error
= copyoutstr(sp
, dp
, ARG_MAX
, &len
)) != 0)
125 if ((error
= copyout(&nullp
, cpp
++, sizeof(nullp
))) != 0)
128 *stackp
= (char *)cpp
;
133 exec_linux_aout_makecmds(struct lwp
*l
, struct exec_package
*epp
)
135 struct exec
*linux_ep
= epp
->ep_hdr
;
139 magic
= LINUX_N_MAGIC(linux_ep
);
140 machtype
= LINUX_N_MACHTYPE(linux_ep
);
143 if (machtype
!= LINUX_MID_MACHINE
)
148 error
= exec_linux_aout_prep_qmagic(l
, epp
);
151 error
= exec_linux_aout_prep_zmagic(l
, epp
);
154 error
= exec_linux_aout_prep_nmagic(l
, epp
);
157 error
= exec_linux_aout_prep_omagic(l
, epp
);
164 * Since text starts at 0x400 in Linux ZMAGIC executables, and 0x400
165 * is very likely not page aligned on most architectures, it is treated
166 * as an NMAGIC here. XXX
170 exec_linux_aout_prep_zmagic(struct lwp
*l
, struct exec_package
*epp
)
172 struct exec
*execp
= epp
->ep_hdr
;
174 epp
->ep_taddr
= LINUX_N_TXTADDR(*execp
, ZMAGIC
);
175 epp
->ep_tsize
= execp
->a_text
;
176 epp
->ep_daddr
= LINUX_N_DATADDR(*execp
, ZMAGIC
);
177 epp
->ep_dsize
= execp
->a_data
+ execp
->a_bss
;
178 epp
->ep_entry
= execp
->a_entry
;
180 /* set up command for text segment */
181 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_readvn
, execp
->a_text
,
182 epp
->ep_taddr
, epp
->ep_vp
, LINUX_N_TXTOFF(*execp
, ZMAGIC
),
183 VM_PROT_READ
|VM_PROT_EXECUTE
);
185 /* set up command for data segment */
186 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_readvn
, execp
->a_data
,
187 epp
->ep_daddr
, epp
->ep_vp
, LINUX_N_DATOFF(*execp
, ZMAGIC
),
188 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
190 /* set up command for bss segment */
192 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_zero
, execp
->a_bss
,
193 epp
->ep_daddr
+ execp
->a_data
, NULLVP
, 0,
194 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
196 return (*epp
->ep_esch
->es_setup_stack
)(l
, epp
);
200 * exec_aout_prep_nmagic(): Prepare Linux NMAGIC package.
201 * Not different from the normal stuff.
205 exec_linux_aout_prep_nmagic(struct lwp
*l
, struct exec_package
*epp
)
207 struct exec
*execp
= epp
->ep_hdr
;
210 epp
->ep_taddr
= LINUX_N_TXTADDR(*execp
, NMAGIC
);
211 epp
->ep_tsize
= execp
->a_text
;
212 epp
->ep_daddr
= LINUX_N_DATADDR(*execp
, NMAGIC
);
213 epp
->ep_dsize
= execp
->a_data
+ execp
->a_bss
;
214 epp
->ep_entry
= execp
->a_entry
;
216 /* set up command for text segment */
217 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_readvn
, execp
->a_text
,
218 epp
->ep_taddr
, epp
->ep_vp
, LINUX_N_TXTOFF(*execp
, NMAGIC
),
219 VM_PROT_READ
|VM_PROT_EXECUTE
);
221 /* set up command for data segment */
222 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_readvn
, execp
->a_data
,
223 epp
->ep_daddr
, epp
->ep_vp
, LINUX_N_DATOFF(*execp
, NMAGIC
),
224 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
226 /* set up command for bss segment */
227 baddr
= roundup(epp
->ep_daddr
+ execp
->a_data
, PAGE_SIZE
);
228 bsize
= epp
->ep_daddr
+ epp
->ep_dsize
- baddr
;
230 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_zero
, bsize
, baddr
,
231 NULLVP
, 0, VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
233 return (*epp
->ep_esch
->es_setup_stack
)(l
, epp
);
237 * exec_aout_prep_omagic(): Prepare Linux OMAGIC package.
242 exec_linux_aout_prep_omagic(struct lwp
*l
, struct exec_package
*epp
)
244 struct exec
*execp
= epp
->ep_hdr
;
245 long dsize
, bsize
, baddr
;
247 epp
->ep_taddr
= LINUX_N_TXTADDR(*execp
, OMAGIC
);
248 epp
->ep_tsize
= execp
->a_text
;
249 epp
->ep_daddr
= LINUX_N_DATADDR(*execp
, OMAGIC
);
250 epp
->ep_dsize
= execp
->a_data
+ execp
->a_bss
;
251 epp
->ep_entry
= execp
->a_entry
;
253 /* set up command for text and data segments */
254 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_readvn
,
255 execp
->a_text
+ execp
->a_data
, epp
->ep_taddr
, epp
->ep_vp
,
256 LINUX_N_TXTOFF(*execp
, OMAGIC
), VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
258 /* set up command for bss segment */
259 baddr
= roundup(epp
->ep_daddr
+ execp
->a_data
, PAGE_SIZE
);
260 bsize
= epp
->ep_daddr
+ epp
->ep_dsize
- baddr
;
262 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_zero
, bsize
, baddr
,
263 NULLVP
, 0, VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
266 * Make sure (# of pages) mapped above equals (vm_tsize + vm_dsize);
267 * obreak(2) relies on this fact. Both `vm_tsize' and `vm_dsize' are
268 * computed (in execve(2)) by rounding *up* `ep_tsize' and `ep_dsize'
269 * respectively to page boundaries.
270 * Compensate `ep_dsize' for the amount of data covered by the last
273 dsize
= epp
->ep_dsize
+ execp
->a_text
- roundup(execp
->a_text
,
275 epp
->ep_dsize
= (dsize
> 0) ? dsize
: 0;
276 return (*epp
->ep_esch
->es_setup_stack
)(l
, epp
);
280 exec_linux_aout_prep_qmagic(struct lwp
*l
, struct exec_package
*epp
)
282 struct exec
*execp
= epp
->ep_hdr
;
285 epp
->ep_taddr
= LINUX_N_TXTADDR(*execp
, QMAGIC
);
286 epp
->ep_tsize
= execp
->a_text
;
287 epp
->ep_daddr
= LINUX_N_DATADDR(*execp
, QMAGIC
);
288 epp
->ep_dsize
= execp
->a_data
+ execp
->a_bss
;
289 epp
->ep_entry
= execp
->a_entry
;
291 error
= vn_marktext(epp
->ep_vp
);
295 /* set up command for text segment */
296 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_pagedvn
, execp
->a_text
,
297 epp
->ep_taddr
, epp
->ep_vp
, LINUX_N_TXTOFF(*execp
, QMAGIC
),
298 VM_PROT_READ
|VM_PROT_EXECUTE
);
300 /* set up command for data segment */
301 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_pagedvn
, execp
->a_data
,
302 epp
->ep_daddr
, epp
->ep_vp
, LINUX_N_DATOFF(*execp
, QMAGIC
),
303 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
305 /* set up command for bss segment */
307 NEW_VMCMD(&epp
->ep_vmcmds
, vmcmd_map_zero
, execp
->a_bss
,
308 epp
->ep_daddr
+ execp
->a_data
, NULLVP
, 0,
309 VM_PROT_READ
|VM_PROT_WRITE
|VM_PROT_EXECUTE
);
311 return (*epp
->ep_esch
->es_setup_stack
)(l
, epp
);