mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
bFLT loader (for uClinux binaries).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1951 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
+6
-1
@@ -171,7 +171,12 @@ LDFLAGS+=-p
|
||||
main.o: CFLAGS+=-p
|
||||
endif
|
||||
|
||||
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
|
||||
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
|
||||
elfload.o linuxload.o
|
||||
ifdef TARGET_HAS_BFLT
|
||||
OBJS+= flatload.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
OBJS+= vm86.o
|
||||
endif
|
||||
|
||||
@@ -773,6 +773,7 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
|
||||
bflt="no"
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
@@ -787,6 +788,7 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
bflt="yes"
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
@@ -842,6 +844,10 @@ if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
|
||||
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
|
||||
fi
|
||||
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
|
||||
echo "TARGET_HAS_BFLT=yes" >> $config_mak
|
||||
echo "#define TARGET_HAS_BFLT 1" >> $config_h
|
||||
fi
|
||||
# sdl defines
|
||||
|
||||
if test "$target_user_only" = "no"; then
|
||||
|
||||
+45
-265
@@ -3,7 +3,6 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -59,19 +58,19 @@ static uint32_t get_elf_hwcap(void)
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_386
|
||||
|
||||
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
|
||||
starts %edx contains a pointer to a function which might be
|
||||
registered using `atexit'. This provides a mean for the
|
||||
dynamic linker to call DT_FINI functions for shared libraries
|
||||
that have been loaded before the code runs.
|
||||
|
||||
A value of 0 tells we have no such handler. */
|
||||
#define ELF_PLAT_INIT(_r) _r->edx = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
|
||||
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
|
||||
starts %edx contains a pointer to a function which might be
|
||||
registered using `atexit'. This provides a mean for the
|
||||
dynamic linker to call DT_FINI functions for shared libraries
|
||||
that have been loaded before the code runs.
|
||||
|
||||
A value of 0 tells we have no such handler. */
|
||||
regs->edx = 0;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -93,8 +92,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#endif
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
target_long stack = infop->start_stack;
|
||||
@@ -107,7 +104,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
regs->ARM_r2 = tgetl(stack + 8); /* envp */
|
||||
regs->ARM_r1 = tgetl(stack + 4); /* envp */
|
||||
/* XXX: it seems that r0 is zeroed after ! */
|
||||
// regs->ARM_r0 = tgetl(stack); /* argc */
|
||||
regs->ARM_r0 = 0;
|
||||
/* For uClinux PIC binaries. */
|
||||
regs->ARM_r10 = infop->start_data;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -142,9 +141,6 @@ enum
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->tstate = 0;
|
||||
@@ -163,9 +159,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->psr = 0;
|
||||
@@ -192,20 +185,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#endif
|
||||
#define ELF_ARCH EM_PPC
|
||||
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
#define ELF_PLAT_INIT(_r) \
|
||||
do { \
|
||||
target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \
|
||||
_r->gpr[3] = bprm->argc; \
|
||||
_r->gpr[4] = (unsigned long)++pos; \
|
||||
for (; tmp != 0; pos++) \
|
||||
tmp = ldl(pos); \
|
||||
_r->gpr[5] = (unsigned long)pos; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* We need to put in some extra aux table entries to tell glibc what
|
||||
* the cache block size is, so it can use the dcbz instruction safely.
|
||||
@@ -239,9 +218,22 @@ do { \
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
||||
{
|
||||
target_ulong pos = infop->start_stack;
|
||||
target_ulong tmp;
|
||||
|
||||
_regs->msr = 1 << MSR_PR; /* Set user mode */
|
||||
_regs->gpr[1] = infop->start_stack;
|
||||
_regs->nip = infop->entry;
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
_regs->gpr[3] = tgetl(pos);
|
||||
pos += sizeof(target_ulong);
|
||||
_regs->gpr[4] = pos;
|
||||
for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
|
||||
tmp = ldl(pos);
|
||||
_regs->gpr[5] = pos;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -263,8 +255,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
||||
#endif
|
||||
#define ELF_ARCH EM_MIPS
|
||||
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->cp0_status = CP0St_UM;
|
||||
@@ -284,8 +274,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_SH
|
||||
|
||||
#define ELF_PLAT_INIT(_r) /* XXXXX */
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
/* Check other registers XXXXX */
|
||||
@@ -308,30 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB w/4KB pages!
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
/*
|
||||
* This structure is used to hold the arguments that are
|
||||
* used when loading binaries.
|
||||
*/
|
||||
struct linux_binprm {
|
||||
char buf[128];
|
||||
void *page[MAX_ARG_PAGES];
|
||||
unsigned long p;
|
||||
int sh_bang;
|
||||
int fd;
|
||||
int e_uid, e_gid;
|
||||
int argc, envc;
|
||||
char * filename; /* Name of binary */
|
||||
unsigned long loader, exec;
|
||||
int dont_iput; /* binfmt handler has put inode */
|
||||
};
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||
@@ -377,8 +341,6 @@ struct exec
|
||||
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
|
||||
|
||||
/* Necessary parameters */
|
||||
#define NGROUPS 32
|
||||
|
||||
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
|
||||
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
@@ -452,13 +414,13 @@ static void bswap_sym(Elf32_Sym *sym)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 'copy_string()' copies argument/envelope strings from user
|
||||
* 'copy_elf_strings()' copies argument/envelope strings from user
|
||||
* memory to free pages in kernel mem. These are in a format ready
|
||||
* to be put directly into the top of new user memory.
|
||||
*
|
||||
*/
|
||||
static unsigned long copy_strings(int argc,char ** argv, void **page,
|
||||
unsigned long p)
|
||||
static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
|
||||
unsigned long p)
|
||||
{
|
||||
char *tmp, *tmp1, *pag = NULL;
|
||||
int len, offset = 0;
|
||||
@@ -506,101 +468,6 @@ static unsigned long copy_strings(int argc,char ** argv, void **page,
|
||||
return p;
|
||||
}
|
||||
|
||||
static int in_group_p(gid_t g)
|
||||
{
|
||||
/* return TRUE if we're in the specified group, FALSE otherwise */
|
||||
int ngroup;
|
||||
int i;
|
||||
gid_t grouplist[NGROUPS];
|
||||
|
||||
ngroup = getgroups(NGROUPS, grouplist);
|
||||
for(i = 0; i < ngroup; i++) {
|
||||
if(grouplist[i] == g) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count(char ** vec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; *vec; i++) {
|
||||
vec++;
|
||||
}
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct stat st;
|
||||
int mode;
|
||||
int retval, id_change;
|
||||
|
||||
if(fstat(bprm->fd, &st) < 0) {
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
mode = st.st_mode;
|
||||
if(!S_ISREG(mode)) { /* Must be regular file */
|
||||
return(-EACCES);
|
||||
}
|
||||
if(!(mode & 0111)) { /* Must have at least one execute bit set */
|
||||
return(-EACCES);
|
||||
}
|
||||
|
||||
bprm->e_uid = geteuid();
|
||||
bprm->e_gid = getegid();
|
||||
id_change = 0;
|
||||
|
||||
/* Set-uid? */
|
||||
if(mode & S_ISUID) {
|
||||
bprm->e_uid = st.st_uid;
|
||||
if(bprm->e_uid != geteuid()) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set-gid? */
|
||||
/*
|
||||
* If setgid is set but no group execute bit then this
|
||||
* is a candidate for mandatory locking, not a setgid
|
||||
* executable.
|
||||
*/
|
||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||
bprm->e_gid = st.st_gid;
|
||||
if (!in_group_p(bprm->e_gid)) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(bprm->buf, 0, sizeof(bprm->buf));
|
||||
retval = lseek(bprm->fd, 0L, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd, bprm->buf, 128);
|
||||
}
|
||||
if(retval < 0) {
|
||||
perror("prepare_binprm");
|
||||
exit(-1);
|
||||
/* return(-errno); */
|
||||
}
|
||||
else {
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
void *host_ptr;
|
||||
|
||||
host_ptr = lock_user(dest, len, 0);
|
||||
memcpy(host_ptr, src, len);
|
||||
unlock_user(host_ptr, dest, 1);
|
||||
}
|
||||
|
||||
unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
|
||||
struct image_info * info)
|
||||
{
|
||||
@@ -628,11 +495,6 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
|
||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
|
||||
if (bprm->loader) {
|
||||
bprm->loader += stack_base;
|
||||
}
|
||||
bprm->exec += stack_base;
|
||||
|
||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||
if (bprm->page[i]) {
|
||||
info->rss++;
|
||||
@@ -703,7 +565,6 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong argv, envp;
|
||||
target_ulong sp;
|
||||
int size;
|
||||
target_ulong u_platform;
|
||||
@@ -765,28 +626,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
|
||||
#endif
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
sp -= (envc + 1) * n;
|
||||
envp = sp;
|
||||
sp -= (argc + 1) * n;
|
||||
argv = sp;
|
||||
if (!ibcs) {
|
||||
sp -= n; tputl(sp, envp);
|
||||
sp -= n; tputl(sp, argv);
|
||||
}
|
||||
sp -= n; tputl(sp, argc);
|
||||
info->arg_start = p;
|
||||
while (argc-->0) {
|
||||
tputl(argv, p); argv += n;
|
||||
p += target_strlen(p) + 1;
|
||||
}
|
||||
tputl(argv, 0);
|
||||
info->arg_end = info->env_start = p;
|
||||
while (envc-->0) {
|
||||
tputl(envp, p); envp += n;
|
||||
p += target_strlen(p) + 1;
|
||||
}
|
||||
tputl(envp, 0);
|
||||
info->env_end = p;
|
||||
sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
|
||||
return sp;
|
||||
}
|
||||
|
||||
@@ -1001,8 +841,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
|
||||
syminfos = s;
|
||||
}
|
||||
|
||||
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
{
|
||||
struct elfhdr elf_ex;
|
||||
struct elfhdr interp_elf_ex;
|
||||
@@ -1034,17 +874,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
bswap_ehdr(&elf_ex);
|
||||
#endif
|
||||
|
||||
if (elf_ex.e_ident[0] != 0x7f ||
|
||||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* First of all, some simple consistency checks */
|
||||
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
|
||||
(! elf_check_arch(elf_ex.e_machine))) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
|
||||
bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
|
||||
bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
|
||||
if (!bprm->p) {
|
||||
retval = -E2BIG;
|
||||
}
|
||||
|
||||
/* Now read in all of the header information */
|
||||
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
|
||||
if (elf_phdata == NULL) {
|
||||
@@ -1188,7 +1030,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
/* OK, we are done with that, now set up the arg stuff,
|
||||
and then start this sucker up */
|
||||
|
||||
if (!bprm->sh_bang) {
|
||||
{
|
||||
char * passed_p;
|
||||
|
||||
if (interpreter_type == INTERPRETER_AOUT) {
|
||||
@@ -1196,7 +1038,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
passed_p = passed_fileno;
|
||||
|
||||
if (elf_interpreter) {
|
||||
bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
|
||||
bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
|
||||
bprm->argc++;
|
||||
}
|
||||
}
|
||||
@@ -1347,11 +1189,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
interp_load_addr,
|
||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||
info);
|
||||
if (interpreter_type == INTERPRETER_AOUT)
|
||||
info->arg_start += strlen(passed_fileno) + 1;
|
||||
info->start_brk = info->brk = elf_brk;
|
||||
info->end_code = end_code;
|
||||
info->start_code = start_code;
|
||||
info->start_data = end_code;
|
||||
info->end_data = end_data;
|
||||
info->start_stack = bprm->p;
|
||||
|
||||
@@ -1380,79 +1221,18 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
|
||||
#ifdef ELF_PLAT_INIT
|
||||
/*
|
||||
* The ABI may specify that certain registers be set up in special
|
||||
* ways (on i386 %edx is the address of a DT_FINI function, for
|
||||
* example. This macro performs whatever initialization to
|
||||
* the regs structure is required.
|
||||
*/
|
||||
ELF_PLAT_INIT(regs);
|
||||
#endif
|
||||
|
||||
|
||||
info->entry = elf_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm.fd = retval;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.sh_bang = 0;
|
||||
bprm.loader = 0;
|
||||
bprm.exec = 0;
|
||||
bprm.dont_iput = 0;
|
||||
bprm.argc = count(argv);
|
||||
bprm.envc = count(envp);
|
||||
|
||||
retval = prepare_binprm(&bprm);
|
||||
|
||||
if(retval>=0) {
|
||||
bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
|
||||
bprm.exec = bprm.p;
|
||||
bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
|
||||
bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
|
||||
if (!bprm.p) {
|
||||
retval = -E2BIG;
|
||||
}
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
retval = load_elf_binary(&bprm,regs,infop);
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Something went wrong, return the inode and free the argument pages*/
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
|
||||
free(bprm.page[i]);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
static int load_aout_interp(void * exptr, int interp_fd)
|
||||
{
|
||||
printf("a.out interpreter not yet supported\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
init_thread(regs, infop);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
|
||||
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
|
||||
* The Silver Hammer Group, Ltd.
|
||||
*
|
||||
* This file provides the definitions and structures needed to
|
||||
* support uClinux flat-format executables.
|
||||
*/
|
||||
|
||||
#define FLAT_VERSION 0x00000004L
|
||||
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
#define MAX_SHARED_LIBS (4)
|
||||
#else
|
||||
#define MAX_SHARED_LIBS (1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To make everything easier to port and manage cross platform
|
||||
* development, all fields are in network byte order.
|
||||
*/
|
||||
|
||||
struct flat_hdr {
|
||||
char magic[4];
|
||||
unsigned long rev; /* version (as above) */
|
||||
unsigned long entry; /* Offset of first executable instruction
|
||||
with text segment from beginning of file */
|
||||
unsigned long data_start; /* Offset of data segment from beginning of
|
||||
file */
|
||||
unsigned long data_end; /* Offset of end of data segment
|
||||
from beginning of file */
|
||||
unsigned long bss_end; /* Offset of end of bss segment from beginning
|
||||
of file */
|
||||
|
||||
/* (It is assumed that data_end through bss_end forms the bss segment.) */
|
||||
|
||||
unsigned long stack_size; /* Size of stack, in bytes */
|
||||
unsigned long reloc_start; /* Offset of relocation records from
|
||||
beginning of file */
|
||||
unsigned long reloc_count; /* Number of relocation records */
|
||||
unsigned long flags;
|
||||
unsigned long build_date; /* When the program/library was built */
|
||||
unsigned long filler[5]; /* Reservered, set to zero */
|
||||
};
|
||||
|
||||
#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */
|
||||
#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
|
||||
#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */
|
||||
#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
|
||||
#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
|
||||
|
||||
|
||||
/*
|
||||
* While it would be nice to keep this header clean, users of older
|
||||
* tools still need this support in the kernel. So this section is
|
||||
* purely for compatibility with old tool chains.
|
||||
*
|
||||
* DO NOT make changes or enhancements to the old format please, just work
|
||||
* with the format above, except to fix bugs with old format support.
|
||||
*/
|
||||
|
||||
#define OLD_FLAT_VERSION 0x00000002L
|
||||
#define OLD_FLAT_RELOC_TYPE_TEXT 0
|
||||
#define OLD_FLAT_RELOC_TYPE_DATA 1
|
||||
#define OLD_FLAT_RELOC_TYPE_BSS 2
|
||||
|
||||
# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,195 @@
|
||||
/* Code for loading Linux executables. Mostly linux kenrel code. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#define NGROUPS 32
|
||||
|
||||
/* ??? This should really be somewhere else. */
|
||||
void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
void *host_ptr;
|
||||
|
||||
host_ptr = lock_user(dest, len, 0);
|
||||
memcpy(host_ptr, src, len);
|
||||
unlock_user(host_ptr, dest, 1);
|
||||
}
|
||||
|
||||
static int in_group_p(gid_t g)
|
||||
{
|
||||
/* return TRUE if we're in the specified group, FALSE otherwise */
|
||||
int ngroup;
|
||||
int i;
|
||||
gid_t grouplist[NGROUPS];
|
||||
|
||||
ngroup = getgroups(NGROUPS, grouplist);
|
||||
for(i = 0; i < ngroup; i++) {
|
||||
if(grouplist[i] == g) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count(char ** vec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; *vec; i++) {
|
||||
vec++;
|
||||
}
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct stat st;
|
||||
int mode;
|
||||
int retval, id_change;
|
||||
|
||||
if(fstat(bprm->fd, &st) < 0) {
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
mode = st.st_mode;
|
||||
if(!S_ISREG(mode)) { /* Must be regular file */
|
||||
return(-EACCES);
|
||||
}
|
||||
if(!(mode & 0111)) { /* Must have at least one execute bit set */
|
||||
return(-EACCES);
|
||||
}
|
||||
|
||||
bprm->e_uid = geteuid();
|
||||
bprm->e_gid = getegid();
|
||||
id_change = 0;
|
||||
|
||||
/* Set-uid? */
|
||||
if(mode & S_ISUID) {
|
||||
bprm->e_uid = st.st_uid;
|
||||
if(bprm->e_uid != geteuid()) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set-gid? */
|
||||
/*
|
||||
* If setgid is set but no group execute bit then this
|
||||
* is a candidate for mandatory locking, not a setgid
|
||||
* executable.
|
||||
*/
|
||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||
bprm->e_gid = st.st_gid;
|
||||
if (!in_group_p(bprm->e_gid)) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(bprm->buf, 0, sizeof(bprm->buf));
|
||||
retval = lseek(bprm->fd, 0L, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd, bprm->buf, 128);
|
||||
}
|
||||
if(retval < 0) {
|
||||
perror("prepare_binprm");
|
||||
exit(-1);
|
||||
/* return(-errno); */
|
||||
}
|
||||
else {
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct the envp and argv tables on the target stack. */
|
||||
target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
|
||||
target_ulong stringp, int push_ptr)
|
||||
{
|
||||
int n = sizeof(target_ulong);
|
||||
target_ulong envp;
|
||||
target_ulong argv;
|
||||
|
||||
sp -= (envc + 1) * n;
|
||||
envp = sp;
|
||||
sp -= (argc + 1) * n;
|
||||
argv = sp;
|
||||
if (push_ptr) {
|
||||
sp -= n; tputl(sp, envp);
|
||||
sp -= n; tputl(sp, argv);
|
||||
}
|
||||
sp -= n; tputl(sp, argc);
|
||||
|
||||
while (argc-- > 0) {
|
||||
tputl(argv, stringp); argv += n;
|
||||
stringp += target_strlen(stringp) + 1;
|
||||
}
|
||||
tputl(argv, 0);
|
||||
while (envc-- > 0) {
|
||||
tputl(envp, stringp); envp += n;
|
||||
stringp += target_strlen(stringp) + 1;
|
||||
}
|
||||
tputl(envp, 0);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm.fd = retval;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.argc = count(argv);
|
||||
bprm.argv = argv;
|
||||
bprm.envc = count(envp);
|
||||
bprm.envp = envp;
|
||||
|
||||
retval = prepare_binprm(&bprm);
|
||||
|
||||
if(retval>=0) {
|
||||
if (bprm.buf[0] == 0x7f
|
||||
&& bprm.buf[1] == 'E'
|
||||
&& bprm.buf[2] == 'L'
|
||||
&& bprm.buf[3] == 'F') {
|
||||
retval = load_elf_binary(&bprm,regs,infop);
|
||||
#if defined(TARGET_HAS_BFLT)
|
||||
} else if (bprm.buf[0] == 'b'
|
||||
&& bprm.buf[1] == 'F'
|
||||
&& bprm.buf[2] == 'L'
|
||||
&& bprm.buf[3] == 'T') {
|
||||
retval = load_flt_binary(&bprm,regs,infop);
|
||||
#endif
|
||||
} else {
|
||||
fprintf(stderr, "Unknown binary format\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
do_init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Something went wrong, return the inode and free the argument pages*/
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
|
||||
free(bprm.page[i]);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
+2
-1
@@ -1545,7 +1545,7 @@ int main(int argc, char **argv)
|
||||
env = cpu_init();
|
||||
global_env = env;
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
_exit(1);
|
||||
}
|
||||
@@ -1556,6 +1556,7 @@ int main(int argc, char **argv)
|
||||
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
|
||||
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
|
||||
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
|
||||
fprintf(logfile, "start_data 0x%08lx\n" , info->start_data);
|
||||
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
|
||||
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
|
||||
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
|
||||
|
||||
+36
-5
@@ -18,6 +18,7 @@
|
||||
struct image_info {
|
||||
unsigned long start_code;
|
||||
unsigned long end_code;
|
||||
unsigned long start_data;
|
||||
unsigned long end_data;
|
||||
unsigned long start_brk;
|
||||
unsigned long brk;
|
||||
@@ -25,10 +26,6 @@ struct image_info {
|
||||
unsigned long mmap;
|
||||
unsigned long rss;
|
||||
unsigned long start_stack;
|
||||
unsigned long arg_start;
|
||||
unsigned long arg_end;
|
||||
unsigned long env_start;
|
||||
unsigned long env_end;
|
||||
unsigned long entry;
|
||||
int personality;
|
||||
};
|
||||
@@ -82,9 +79,43 @@ typedef struct TaskState {
|
||||
extern TaskState *first_task_state;
|
||||
extern const char *qemu_uname_release;
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
/* ??? See if we can avoid exposing so much of the loader internals. */
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB w/4KB pages!
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
/*
|
||||
* This structure is used to hold the arguments that are
|
||||
* used when loading binaries.
|
||||
*/
|
||||
struct linux_binprm {
|
||||
char buf[128];
|
||||
void *page[MAX_ARG_PAGES];
|
||||
unsigned long p;
|
||||
int fd;
|
||||
int e_uid, e_gid;
|
||||
int argc, envc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
char * filename; /* Name of binary */
|
||||
};
|
||||
|
||||
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
|
||||
target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
|
||||
target_ulong stringp, int push_ptr);
|
||||
int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop);
|
||||
|
||||
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info);
|
||||
int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info);
|
||||
|
||||
void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len);
|
||||
void target_set_brk(target_ulong new_brk);
|
||||
long do_brk(target_ulong new_brk);
|
||||
void syscall_init(void);
|
||||
|
||||
Reference in New Issue
Block a user