* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2006 CodeSourcery.
* Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
#include "qemu.h"
#include "flat.h"
+#define ntohl(x) be32_to_cpu(x)
+#include <target_flat.h>
//#define DEBUG
#ifdef DEBUG
-#define DBG_FLT(a...) printf(a)
-#else
-#define DBG_FLT(a...)
-#endif
-
-#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
-#define flat_old_ram_flag(flag) (flag)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define flat_get_relocate_addr(relval) (relval)
+#define DBG_FLT(...) printf(__VA_ARGS__)
#else
-#define flat_get_relocate_addr(relval) bswap32(relval)
+#define DBG_FLT(...)
#endif
#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */
struct lib_info {
- target_ulong start_code; /* Start of text segment */
- target_ulong start_data; /* Start of data segment */
- target_ulong end_data; /* Start of bss section */
- target_ulong start_brk; /* End of data segment */
- target_ulong text_len; /* Length of text segment */
- target_ulong entry; /* Start address for this module */
- target_ulong build_date; /* When this one was compiled */
+ abi_ulong start_code; /* Start of text segment */
+ abi_ulong start_data; /* Start of data segment */
+ abi_ulong end_data; /* Start of bss section */
+ abi_ulong start_brk; /* End of data segment */
+ abi_ulong text_len; /* Length of text segment */
+ abi_ulong entry; /* Start address for this module */
+ abi_ulong build_date; /* When this one was compiled */
short loaded; /* Has this library been loaded? */
};
struct linux_binprm;
-#define ntohl(x) be32_to_cpu(x)
-
/****************************************************************************/
/*
* create_flat_tables() parses the env- and arg-strings in new user
*/
/* Push a block of strings onto the guest stack. */
-static target_ulong copy_strings(target_ulong p, int n, char **s)
+static abi_ulong copy_strings(abi_ulong p, int n, char **s)
{
int len;
return p;
}
-int target_pread(int fd, target_ulong ptr, target_ulong len,
- target_ulong offset)
+static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
+ abi_ulong offset)
{
void *buf;
int ret;
- buf = lock_user(ptr, len, 0);
+ buf = lock_user(VERIFY_WRITE, ptr, len, 0);
ret = pread(fd, buf, len, offset);
unlock_user(buf, ptr, len);
return ret;
/****************************************************************************/
-static target_ulong
-calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
+static abi_ulong
+calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
{
- target_ulong addr;
+ abi_ulong addr;
int id;
- target_ulong start_brk;
- target_ulong start_data;
- target_ulong text_len;
- target_ulong start_code;
+ abi_ulong start_brk;
+ abi_ulong start_data;
+ abi_ulong text_len;
+ abi_ulong start_code;
#ifdef CONFIG_BINFMT_SHARED_FLAT
#error needs checking
/****************************************************************************/
/* ??? This does not handle endianness correctly. */
-void old_reloc(struct lib_info *libinfo, uint32_t rl)
+static void old_reloc(struct lib_info *libinfo, uint32_t rl)
{
#ifdef DEBUG
- char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
+ const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
#endif
uint32_t *ptr;
uint32_t offset;
reloc_type = rl >> 30;
/* ??? How to handle this? */
#if defined(CONFIG_COLDFIRE)
- ptr = (uint32_t *) (libinfo->start_code + offset);
+ ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset);
#else
- ptr = (uint32_t *) (libinfo->start_data + offset);
+ ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset);
#endif
#ifdef DEBUG
"(address %p, currently %x) into segment %s\n",
offset, ptr, (int)*ptr, segment[reloc_type]);
#endif
-
+
switch (reloc_type) {
case OLD_FLAT_RELOC_TYPE_TEXT:
*ptr += libinfo->start_code;
break;
}
DBG_FLT("Relocation became %x\n", (int)*ptr);
-}
+}
/****************************************************************************/
static int load_flat_file(struct linux_binprm * bprm,
- struct lib_info *libinfo, int id, target_ulong *extra_stack)
+ struct lib_info *libinfo, int id, abi_ulong *extra_stack)
{
struct flat_hdr * hdr;
- target_ulong textpos = 0, datapos = 0, result;
- target_ulong realdatastart = 0;
- target_ulong text_len, data_len, bss_len, stack_len, flags;
- target_ulong memp = 0; /* for finding the brk area */
- target_ulong extra;
- target_ulong reloc = 0, rp;
+ abi_ulong textpos = 0, datapos = 0;
+ abi_long result;
+ abi_ulong realdatastart = 0;
+ abi_ulong text_len, data_len, bss_len, stack_len, flags;
+ abi_ulong extra;
+ abi_ulong reloc = 0, rp;
int i, rev, relocs = 0;
- target_ulong fpos;
- target_ulong start_code, end_code;
+ abi_ulong fpos;
+ abi_ulong start_code;
+ abi_ulong indx_len;
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
rev, (int) FLAT_VERSION);
return -ENOEXEC;
}
-
+
/* Don't allow old format executables to use shared libraries */
if (rev == OLD_FLAT_VERSION && id != 0) {
fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
/*
* calculate the extra space we need to map in
*/
- extra = relocs * sizeof(target_ulong);
+ extra = relocs * sizeof(abi_ulong);
if (extra < bss_len + stack_len)
extra = bss_len + stack_len;
+ /* Add space for library base pointers. Make sure this does not
+ misalign the doesn't misalign the data segment. */
+ indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
+ indx_len = (indx_len + 15) & ~(abi_ulong)15;
+
/*
* there are a couple of cases here, the separate code/data
* case, and then the fully copied to RAM case which lumps
textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
MAP_PRIVATE, bprm->fd, 0);
- if (textpos == -1) {
+ if (textpos == -1) {
fprintf(stderr, "Unable to mmap process text\n");
return -1;
}
- realdatastart = target_mmap(0, data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
+ realdatastart = target_mmap(0, data_len + extra + indx_len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
fprintf(stderr, "Unable to allocate RAM for process data\n");
return realdatastart;
}
- datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+ datapos = realdatastart + indx_len;
DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
(int)(data_len + bss_len + stack_len), (int)datapos);
fpos = ntohl(hdr->data_start);
#ifdef CONFIG_BINFMT_ZFLAT
if (flags & FLAT_FLAG_GZDATA) {
- result = decompress_exec(bprm, fpos, (char *) datapos,
- data_len + (relocs * sizeof(target_ulong)))
+ result = decompress_exec(bprm, fpos, (char *) datapos,
+ data_len + (relocs * sizeof(abi_ulong)))
} else
#endif
{
result = target_pread(bprm->fd, datapos,
- data_len + (relocs * sizeof(target_ulong)),
+ data_len + (relocs * sizeof(abi_ulong)),
fpos);
}
if (result < 0) {
}
reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
- memp = realdatastart;
} else {
- textpos = target_mmap(0, text_len + data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
+ textpos = target_mmap(0, text_len + data_len + extra + indx_len,
PROT_READ | PROT_EXEC | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (textpos == -1 ) {
}
realdatastart = textpos + ntohl(hdr->data_start);
- datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
- reloc = (textpos + ntohl(hdr->reloc_start) +
- MAX_SHARED_LIBS * sizeof(target_ulong));
- memp = textpos;
+ datapos = realdatastart + indx_len;
+ reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
#ifdef CONFIG_BINFMT_ZFLAT
#error code needs checking
text_len, 0);
if (result >= 0) {
result = target_pread(bprm->fd, datapos,
- data_len + (relocs * sizeof(target_ulong)),
+ data_len + (relocs * sizeof(abi_ulong)),
ntohl(hdr->data_start));
}
}
/* The main program needs a little extra setup in the task structure */
start_code = textpos + sizeof (struct flat_hdr);
- end_code = textpos + text_len;
DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
id ? "Lib" : "Load", bprm->filename,
- (int) start_code, (int) end_code,
+ (int) start_code, (int) (textpos + text_len),
(int) datapos,
(int) (datapos + data_len),
(int) (datapos + data_len),
libinfo[id].loaded = 1;
libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
libinfo[id].build_date = ntohl(hdr->build_date);
-
+
/*
* We just load the allocations into some temporary memory to
* help simplify all this mumbo jumbo
*
* We've got two different sections of relocation entries.
- * The first is the GOT which resides at the begining of the data segment
+ * The first is the GOT which resides at the beginning of the data segment
* and is terminated with a -1. This one can be relocated in place.
* The second is the extra relocation entries tacked after the image's
* data segment. These require a little more processing as the entry is
if (flags & FLAT_FLAG_GOTPIC) {
rp = datapos;
while (1) {
- target_ulong addr;
- addr = tgetl(rp);
+ abi_ulong addr;
+ if (get_user_ual(addr, rp))
+ return -EFAULT;
if (addr == -1)
break;
if (addr) {
addr = calc_reloc(addr, libinfo, id, 0);
if (addr == RELOC_FAILED)
return -ENOEXEC;
- tputl(rp, addr);
+ if (put_user_ual(addr, rp))
+ return -EFAULT;
}
- rp += sizeof(target_ulong);
+ rp += sizeof(abi_ulong);
}
}
* __start to address 4 so that is okay).
*/
if (rev > OLD_FLAT_VERSION) {
+ abi_ulong persistent = 0;
for (i = 0; i < relocs; i++) {
- target_ulong addr, relval;
+ abi_ulong addr, relval;
/* Get the address of the pointer to be
relocated (of course, the address has to be
relocated first). */
- relval = tgetl(reloc + i * sizeof (target_ulong));
+ if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+ return -EFAULT;
+ relval = ntohl(relval);
+ if (flat_set_persistent(relval, &persistent))
+ continue;
addr = flat_get_relocate_addr(relval);
rp = calc_reloc(addr, libinfo, id, 1);
if (rp == RELOC_FAILED)
return -ENOEXEC;
/* Get the pointer's value. */
- addr = tgetl(rp);
+ if (get_user_ual(addr, rp))
+ return -EFAULT;
+ addr = flat_get_addr_from_rp(rp, relval, flags, &persistent);
if (addr != 0) {
/*
* Do the relocation. PIC relocs in the data section are
* already in target order
*/
-
-#ifndef TARGET_WORDS_BIGENDIAN
if ((flags & FLAT_FLAG_GOTPIC) == 0)
- addr = bswap32(addr);
-#endif
+ addr = ntohl(addr);
addr = calc_reloc(addr, libinfo, id, 0);
if (addr == RELOC_FAILED)
return -ENOEXEC;
/* Write back the relocated pointer. */
- tputl(rp, addr);
+ if (flat_put_addr_at_rp(rp, addr, relval))
+ return -EFAULT;
}
}
} else {
for (i = 0; i < relocs; i++) {
- target_ulong relval;
- relval = tgetl(reloc + i * sizeof (target_ulong));
+ abi_ulong relval;
+ if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
+ return -EFAULT;
old_reloc(&libinfo[0], relval);
}
}
-
+
/* zero the BSS. */
- memset((void*)(datapos + data_len), 0, bss_len);
+ memset(g2h(datapos + data_len), 0, bss_len);
return 0;
}
struct image_info * info)
{
struct lib_info libinfo[MAX_SHARED_LIBS];
- target_ulong p = bprm->p;
- target_ulong stack_len;
- target_ulong start_addr;
- target_ulong sp;
+ abi_ulong p = bprm->p;
+ abi_ulong stack_len;
+ abi_ulong start_addr;
+ abi_ulong sp;
int res;
int i, j;
* pedantic and include space for the argv/envp array as it may have
* a lot of entries.
*/
-#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
- stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
+ stack_len = 0;
+ for (i = 0; i < bprm->argc; ++i) {
+ /* the argv strings */
+ stack_len += strlen(bprm->argv[i]);
+ }
+ for (i = 0; i < bprm->envc; ++i) {
+ /* the envp strings */
+ stack_len += strlen(bprm->envp[i]);
+ }
stack_len += (bprm->argc + 1) * 4; /* the argv array */
stack_len += (bprm->envc + 1) * 4; /* the envp array */
-
+
res = load_flat_file(bprm, libinfo, 0, &stack_len);
if (res > (unsigned long)-4096)
return res;
-
+
/* Update data segment pointers for all libraries */
for (i=0; i<MAX_SHARED_LIBS; i++) {
if (libinfo[i].loaded) {
- target_ulong p;
+ abi_ulong p;
p = libinfo[i].start_data;
for (j=0; j<MAX_SHARED_LIBS; j++) {
p -= 4;
- tput32(p, libinfo[j].loaded
- ? libinfo[j].start_data
- : UNLOADED_LIB);
+ /* FIXME - handle put_user() failures */
+ if (put_user_ual(libinfo[j].loaded
+ ? libinfo[j].start_data
+ : UNLOADED_LIB,
+ p))
+ return -EFAULT;
}
}
}
DBG_FLT("p=%x\n", (int)p);
/* Copy argv/envp. */
- p = copy_strings(p, bprm->argc, bprm->argv);
p = copy_strings(p, bprm->envc, bprm->envp);
+ p = copy_strings(p, bprm->argc, bprm->argv);
/* Align stack. */
- sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
- sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
-
+ sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1);
+ /* Enforce final stack alignment of 16 bytes. This is sufficient
+ for all current targets, and excess alignment is harmless. */
+ stack_len = bprm->envc + bprm->argc + 2;
+ stack_len += 3; /* argc, arvg, argp */
+ stack_len *= sizeof(abi_ulong);
+ if ((sp + stack_len) & 15)
+ sp -= 16 - ((sp + stack_len) & 15);
+ sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
+ flat_argvp_envp_on_stack());
+
/* Fake some return addresses to ensure the call chain will
* initialise library in order for us. We are required to call
* lib 1 first, then 2, ... and finally the main program (id 0).
for (i = MAX_SHARED_LIBS-1; i>0; i--) {
if (libinfo[i].loaded) {
/* Push previos first to call address */
- --sp; put_user(start_addr, sp);
+ --sp;
+ if (put_user_ual(start_addr, sp))
+ return -EFAULT;
start_addr = libinfo[i].entry;
}
}
#endif
-
+
/* Stash our initial stack pointer into the mm structure */
info->start_code = libinfo[0].start_code;
info->end_code = libinfo[0].start_code = libinfo[0].text_len;
info->end_data = libinfo[0].end_data;
info->start_brk = libinfo[0].start_brk;
info->start_stack = sp;
+ info->stack_limit = libinfo[0].start_brk;
info->entry = start_addr;
+ info->code_offset = info->start_code;
+ info->data_offset = info->start_data - libinfo[0].text_len;
+
DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
(int)info->entry, (int)info->start_stack);
-
+
return 0;
}