cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

flatload.c (26206B)


      1/****************************************************************************/
      2/*
      3 *  QEMU bFLT binary loader.  Based on linux/fs/binfmt_flat.c
      4 *
      5 *  This program is free software; you can redistribute it and/or modify
      6 *  it under the terms of the GNU General Public License as published by
      7 *  the Free Software Foundation; either version 2 of the License, or
      8 *  (at your option) any later version.
      9 *
     10 *  This program is distributed in the hope that it will be useful,
     11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 *  GNU General Public License for more details.
     14 *
     15 *  You should have received a copy of the GNU General Public License
     16 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 *
     18 *      Copyright (C) 2006 CodeSourcery.
     19 *	Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
     20 *	Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
     21 *	Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
     22 *	Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
     23 *  based heavily on:
     24 *
     25 *  linux/fs/binfmt_aout.c:
     26 *      Copyright (C) 1991, 1992, 1996  Linus Torvalds
     27 *  linux/fs/binfmt_flat.c for 2.0 kernel
     28 *	    Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
     29 *	JAN/99 -- coded full program relocation (gerg@snapgear.com)
     30 */
     31
     32/* ??? ZFLAT and shared library support is currently disabled.  */
     33
     34/****************************************************************************/
     35
     36#include "qemu/osdep.h"
     37
     38#include "qemu.h"
     39#include "user-internals.h"
     40#include "loader.h"
     41#include "user-mmap.h"
     42#include "flat.h"
     43#include "target_flat.h"
     44
     45//#define DEBUG
     46
     47#ifdef DEBUG
     48#define	DBG_FLT(...)	printf(__VA_ARGS__)
     49#else
     50#define	DBG_FLT(...)
     51#endif
     52
     53#define RELOC_FAILED 0xff00ff01		/* Relocation incorrect somewhere */
     54#define UNLOADED_LIB 0x7ff000ff		/* Placeholder for unused library */
     55
     56struct lib_info {
     57    abi_ulong start_code;       /* Start of text segment */
     58    abi_ulong start_data;       /* Start of data segment */
     59    abi_ulong end_data;         /* Start of bss section */
     60    abi_ulong start_brk;        /* End of data segment */
     61    abi_ulong text_len;	        /* Length of text segment */
     62    abi_ulong entry;	        /* Start address for this module */
     63    abi_ulong build_date;       /* When this one was compiled */
     64    short loaded;		/* Has this library been loaded? */
     65};
     66
     67#ifdef CONFIG_BINFMT_SHARED_FLAT
     68static int load_flat_shared_library(int id, struct lib_info *p);
     69#endif
     70
     71struct linux_binprm;
     72
     73/****************************************************************************/
     74/*
     75 * create_flat_tables() parses the env- and arg-strings in new user
     76 * memory and creates the pointer tables from them, and puts their
     77 * addresses on the "stack", returning the new stack pointer value.
     78 */
     79
     80/* Push a block of strings onto the guest stack.  */
     81static abi_ulong copy_strings(abi_ulong p, int n, char **s)
     82{
     83    int len;
     84
     85    while (n-- > 0) {
     86        len = strlen(s[n]) + 1;
     87        p -= len;
     88        memcpy_to_target(p, s[n], len);
     89    }
     90
     91    return p;
     92}
     93
     94static int target_pread(int fd, abi_ulong ptr, abi_ulong len,
     95                        abi_ulong offset)
     96{
     97    void *buf;
     98    int ret;
     99
    100    buf = lock_user(VERIFY_WRITE, ptr, len, 0);
    101    if (!buf) {
    102        return -EFAULT;
    103    }
    104    ret = pread(fd, buf, len, offset);
    105    if (ret < 0) {
    106        ret = -errno;
    107    }
    108    unlock_user(buf, ptr, len);
    109    return ret;
    110}
    111/****************************************************************************/
    112
    113#ifdef CONFIG_BINFMT_ZFLAT
    114
    115#include <linux/zlib.h>
    116
    117#define LBUFSIZE	4000
    118
    119/* gzip flag byte */
    120#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
    121#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
    122#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
    123#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
    124#define COMMENT      0x10 /* bit 4 set: file comment present */
    125#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
    126#define RESERVED     0xC0 /* bit 6,7:   reserved */
    127
    128static int decompress_exec(
    129	struct linux_binprm *bprm,
    130	unsigned long offset,
    131	char *dst,
    132	long len,
    133	int fd)
    134{
    135	unsigned char *buf;
    136	z_stream strm;
    137	loff_t fpos;
    138	int ret, retval;
    139
    140	DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
    141
    142	memset(&strm, 0, sizeof(strm));
    143	strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
    144	if (strm.workspace == NULL) {
    145		DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
    146		return -ENOMEM;
    147	}
    148	buf = kmalloc(LBUFSIZE, GFP_KERNEL);
    149	if (buf == NULL) {
    150		DBG_FLT("binfmt_flat: no memory for read buffer\n");
    151		retval = -ENOMEM;
    152		goto out_free;
    153	}
    154
    155	/* Read in first chunk of data and parse gzip header. */
    156	fpos = offset;
    157	ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
    158
    159	strm.next_in = buf;
    160	strm.avail_in = ret;
    161	strm.total_in = 0;
    162
    163	retval = -ENOEXEC;
    164
    165	/* Check minimum size -- gzip header */
    166	if (ret < 10) {
    167		DBG_FLT("binfmt_flat: file too small?\n");
    168		goto out_free_buf;
    169	}
    170
    171	/* Check gzip magic number */
    172	if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
    173		DBG_FLT("binfmt_flat: unknown compression magic?\n");
    174		goto out_free_buf;
    175	}
    176
    177	/* Check gzip method */
    178	if (buf[2] != 8) {
    179		DBG_FLT("binfmt_flat: unknown compression method?\n");
    180		goto out_free_buf;
    181	}
    182	/* Check gzip flags */
    183	if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
    184	    (buf[3] & RESERVED)) {
    185		DBG_FLT("binfmt_flat: unknown flags?\n");
    186		goto out_free_buf;
    187	}
    188
    189	ret = 10;
    190	if (buf[3] & EXTRA_FIELD) {
    191		ret += 2 + buf[10] + (buf[11] << 8);
    192		if (unlikely(LBUFSIZE == ret)) {
    193			DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
    194			goto out_free_buf;
    195		}
    196	}
    197	if (buf[3] & ORIG_NAME) {
    198		for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
    199			;
    200		if (unlikely(LBUFSIZE == ret)) {
    201			DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
    202			goto out_free_buf;
    203		}
    204	}
    205	if (buf[3] & COMMENT) {
    206		for (;  ret < LBUFSIZE && (buf[ret] != 0); ret++)
    207			;
    208		if (unlikely(LBUFSIZE == ret)) {
    209			DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
    210			goto out_free_buf;
    211		}
    212	}
    213
    214	strm.next_in += ret;
    215	strm.avail_in -= ret;
    216
    217	strm.next_out = dst;
    218	strm.avail_out = len;
    219	strm.total_out = 0;
    220
    221	if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
    222		DBG_FLT("binfmt_flat: zlib init failed?\n");
    223		goto out_free_buf;
    224	}
    225
    226	while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
    227		ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
    228		if (ret <= 0)
    229			break;
    230                if (is_error(ret)) {
    231			break;
    232                }
    233		len -= ret;
    234
    235		strm.next_in = buf;
    236		strm.avail_in = ret;
    237		strm.total_in = 0;
    238	}
    239
    240	if (ret < 0) {
    241		DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
    242			ret, strm.msg);
    243		goto out_zlib;
    244	}
    245
    246	retval = 0;
    247out_zlib:
    248	zlib_inflateEnd(&strm);
    249out_free_buf:
    250	kfree(buf);
    251out_free:
    252	kfree(strm.workspace);
    253out:
    254	return retval;
    255}
    256
    257#endif /* CONFIG_BINFMT_ZFLAT */
    258
    259/****************************************************************************/
    260
    261static abi_ulong
    262calc_reloc(abi_ulong r, struct lib_info *p, int curid, int internalp)
    263{
    264    abi_ulong addr;
    265    int id;
    266    abi_ulong start_brk;
    267    abi_ulong start_data;
    268    abi_ulong text_len;
    269    abi_ulong start_code;
    270
    271#ifdef CONFIG_BINFMT_SHARED_FLAT
    272#error needs checking
    273    if (r == 0)
    274        id = curid;	/* Relocs of 0 are always self referring */
    275    else {
    276        id = (r >> 24) & 0xff;	/* Find ID for this reloc */
    277        r &= 0x00ffffff;	/* Trim ID off here */
    278    }
    279    if (id >= MAX_SHARED_LIBS) {
    280        fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
    281                (unsigned) r, id);
    282        goto failed;
    283    }
    284    if (curid != id) {
    285        if (internalp) {
    286            fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
    287                    "in same module (%d != %d)\n",
    288                    (unsigned) r, curid, id);
    289            goto failed;
    290        } else if (!p[id].loaded && is_error(load_flat_shared_library(id, p))) {
    291            fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
    292            goto failed;
    293        }
    294        /* Check versioning information (i.e. time stamps) */
    295        if (p[id].build_date && p[curid].build_date
    296            && p[curid].build_date < p[id].build_date) {
    297            fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
    298                    id, curid);
    299            goto failed;
    300        }
    301    }
    302#else
    303    id = 0;
    304#endif
    305
    306    start_brk = p[id].start_brk;
    307    start_data = p[id].start_data;
    308    start_code = p[id].start_code;
    309    text_len = p[id].text_len;
    310
    311    if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
    312        fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
    313                "(0 - 0x%x/0x%x)\n",
    314               (int) r,(int)(start_brk-start_code),(int)text_len);
    315        goto failed;
    316    }
    317
    318    if (r < text_len)			/* In text segment */
    319        addr = r + start_code;
    320    else					/* In data segment */
    321        addr = r - text_len + start_data;
    322
    323    /* Range checked already above so doing the range tests is redundant...*/
    324    return(addr);
    325
    326failed:
    327    abort();
    328    return RELOC_FAILED;
    329}
    330
    331/****************************************************************************/
    332
    333/* ??? This does not handle endianness correctly.  */
    334static void old_reloc(struct lib_info *libinfo, uint32_t rl)
    335{
    336#ifdef DEBUG
    337	const char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
    338#endif
    339	uint32_t *ptr;
    340        uint32_t offset;
    341        int reloc_type;
    342
    343        offset = rl & 0x3fffffff;
    344        reloc_type = rl >> 30;
    345        /* ??? How to handle this?  */
    346#if defined(CONFIG_COLDFIRE)
    347	ptr = (uint32_t *) ((unsigned long) libinfo->start_code + offset);
    348#else
    349	ptr = (uint32_t *) ((unsigned long) libinfo->start_data + offset);
    350#endif
    351
    352#ifdef DEBUG
    353	fprintf(stderr, "Relocation of variable at DATASEG+%x "
    354		"(address %p, currently %x) into segment %s\n",
    355		offset, ptr, (int)*ptr, segment[reloc_type]);
    356#endif
    357
    358	switch (reloc_type) {
    359	case OLD_FLAT_RELOC_TYPE_TEXT:
    360		*ptr += libinfo->start_code;
    361		break;
    362	case OLD_FLAT_RELOC_TYPE_DATA:
    363		*ptr += libinfo->start_data;
    364		break;
    365	case OLD_FLAT_RELOC_TYPE_BSS:
    366		*ptr += libinfo->end_data;
    367		break;
    368	default:
    369		fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
    370                        reloc_type);
    371		break;
    372	}
    373	DBG_FLT("Relocation became %x\n", (int)*ptr);
    374}
    375
    376/****************************************************************************/
    377
    378static int load_flat_file(struct linux_binprm * bprm,
    379		struct lib_info *libinfo, int id, abi_ulong *extra_stack)
    380{
    381    struct flat_hdr * hdr;
    382    abi_ulong textpos = 0, datapos = 0;
    383    abi_long result;
    384    abi_ulong realdatastart = 0;
    385    abi_ulong text_len, data_len, bss_len, stack_len, flags;
    386    abi_ulong extra;
    387    abi_ulong reloc = 0, rp;
    388    int i, rev, relocs = 0;
    389    abi_ulong fpos;
    390    abi_ulong start_code;
    391    abi_ulong indx_len;
    392
    393    hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
    394
    395    text_len  = ntohl(hdr->data_start);
    396    data_len  = ntohl(hdr->data_end) - ntohl(hdr->data_start);
    397    bss_len   = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
    398    stack_len = ntohl(hdr->stack_size);
    399    if (extra_stack) {
    400        stack_len += *extra_stack;
    401        *extra_stack = stack_len;
    402    }
    403    relocs    = ntohl(hdr->reloc_count);
    404    flags     = ntohl(hdr->flags);
    405    rev       = ntohl(hdr->rev);
    406
    407    DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
    408
    409    if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
    410        fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
    411                rev, (int) FLAT_VERSION);
    412        return -ENOEXEC;
    413    }
    414
    415    /* Don't allow old format executables to use shared libraries */
    416    if (rev == OLD_FLAT_VERSION && id != 0) {
    417        fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
    418        return -ENOEXEC;
    419    }
    420
    421    /*
    422     * fix up the flags for the older format,  there were all kinds
    423     * of endian hacks,  this only works for the simple cases
    424     */
    425    if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
    426        flags = FLAT_FLAG_RAM;
    427
    428#ifndef CONFIG_BINFMT_ZFLAT
    429    if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
    430        fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
    431        return -ENOEXEC;
    432    }
    433#endif
    434
    435    /*
    436     * calculate the extra space we need to map in
    437     */
    438    extra = relocs * sizeof(abi_ulong);
    439    if (extra < bss_len + stack_len)
    440        extra = bss_len + stack_len;
    441
    442    /* Add space for library base pointers.  Make sure this does not
    443       misalign the  doesn't misalign the data segment.  */
    444    indx_len = MAX_SHARED_LIBS * sizeof(abi_ulong);
    445    indx_len = (indx_len + 15) & ~(abi_ulong)15;
    446
    447    /*
    448     * Allocate the address space.
    449     */
    450    probe_guest_base(bprm->filename, 0,
    451                     text_len + data_len + extra + indx_len);
    452
    453    /*
    454     * there are a couple of cases here,  the separate code/data
    455     * case,  and then the fully copied to RAM case which lumps
    456     * it all together.
    457     */
    458    if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
    459        /*
    460         * this should give us a ROM ptr,  but if it doesn't we don't
    461         * really care
    462         */
    463        DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
    464
    465        textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
    466                              MAP_PRIVATE, bprm->fd, 0);
    467        if (textpos == -1) {
    468            fprintf(stderr, "Unable to mmap process text\n");
    469            return -1;
    470        }
    471
    472        realdatastart = target_mmap(0, data_len + extra + indx_len,
    473                                    PROT_READ|PROT_WRITE|PROT_EXEC,
    474                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    475
    476        if (realdatastart == -1) {
    477            fprintf(stderr, "Unable to allocate RAM for process data\n");
    478            return realdatastart;
    479        }
    480        datapos = realdatastart + indx_len;
    481
    482        DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
    483                        (int)(data_len + bss_len + stack_len), (int)datapos);
    484
    485        fpos = ntohl(hdr->data_start);
    486#ifdef CONFIG_BINFMT_ZFLAT
    487        if (flags & FLAT_FLAG_GZDATA) {
    488            result = decompress_exec(bprm, fpos, (char *) datapos,
    489                                     data_len + (relocs * sizeof(abi_ulong)))
    490        } else
    491#endif
    492        {
    493            result = target_pread(bprm->fd, datapos,
    494                                  data_len + (relocs * sizeof(abi_ulong)),
    495                                  fpos);
    496        }
    497        if (result < 0) {
    498            fprintf(stderr, "Unable to read data+bss\n");
    499            return result;
    500        }
    501
    502        reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
    503
    504    } else {
    505
    506        textpos = target_mmap(0, text_len + data_len + extra + indx_len,
    507                              PROT_READ | PROT_EXEC | PROT_WRITE,
    508                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    509        if (textpos == -1 ) {
    510            fprintf(stderr, "Unable to allocate RAM for process text/data\n");
    511            return -1;
    512        }
    513
    514        realdatastart = textpos + ntohl(hdr->data_start);
    515        datapos = realdatastart + indx_len;
    516        reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
    517
    518#ifdef CONFIG_BINFMT_ZFLAT
    519#error code needs checking
    520        /*
    521         * load it all in and treat it like a RAM load from now on
    522         */
    523        if (flags & FLAT_FLAG_GZIP) {
    524                result = decompress_exec(bprm, sizeof (struct flat_hdr),
    525                                 (((char *) textpos) + sizeof (struct flat_hdr)),
    526                                 (text_len + data_len + (relocs * sizeof(unsigned long))
    527                                          - sizeof (struct flat_hdr)),
    528                                 0);
    529                memmove((void *) datapos, (void *) realdatastart,
    530                                data_len + (relocs * sizeof(unsigned long)));
    531        } else if (flags & FLAT_FLAG_GZDATA) {
    532                fpos = 0;
    533                result = bprm->file->f_op->read(bprm->file,
    534                                (char *) textpos, text_len, &fpos);
    535                if (!is_error(result)) {
    536                        result = decompress_exec(bprm, text_len, (char *) datapos,
    537                                         data_len + (relocs * sizeof(unsigned long)), 0);
    538                }
    539        }
    540        else
    541#endif
    542        {
    543            result = target_pread(bprm->fd, textpos,
    544                                  text_len, 0);
    545            if (result >= 0) {
    546                result = target_pread(bprm->fd, datapos,
    547                    data_len + (relocs * sizeof(abi_ulong)),
    548                    ntohl(hdr->data_start));
    549            }
    550        }
    551        if (result < 0) {
    552            fprintf(stderr, "Unable to read code+data+bss\n");
    553            return result;
    554        }
    555    }
    556
    557    DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n",
    558            (int)textpos, 0x00ffffff&ntohl(hdr->entry),
    559            ntohl(hdr->data_start));
    560
    561    /* The main program needs a little extra setup in the task structure */
    562    start_code = textpos + sizeof (struct flat_hdr);
    563
    564    DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
    565            id ? "Lib" : "Load", bprm->filename,
    566            (int) start_code, (int) (textpos + text_len),
    567            (int) datapos,
    568            (int) (datapos + data_len),
    569            (int) (datapos + data_len),
    570            (int) (((datapos + data_len + bss_len) + 3) & ~3));
    571
    572    text_len -= sizeof(struct flat_hdr); /* the real code len */
    573
    574    /* Store the current module values into the global library structure */
    575    libinfo[id].start_code = start_code;
    576    libinfo[id].start_data = datapos;
    577    libinfo[id].end_data = datapos + data_len;
    578    libinfo[id].start_brk = datapos + data_len + bss_len;
    579    libinfo[id].text_len = text_len;
    580    libinfo[id].loaded = 1;
    581    libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
    582    libinfo[id].build_date = ntohl(hdr->build_date);
    583
    584    /*
    585     * We just load the allocations into some temporary memory to
    586     * help simplify all this mumbo jumbo
    587     *
    588     * We've got two different sections of relocation entries.
    589     * The first is the GOT which resides at the beginning of the data segment
    590     * and is terminated with a -1.  This one can be relocated in place.
    591     * The second is the extra relocation entries tacked after the image's
    592     * data segment. These require a little more processing as the entry is
    593     * really an offset into the image which contains an offset into the
    594     * image.
    595     */
    596    if (flags & FLAT_FLAG_GOTPIC) {
    597        rp = datapos;
    598        while (1) {
    599            abi_ulong addr;
    600            if (get_user_ual(addr, rp))
    601                return -EFAULT;
    602            if (addr == -1)
    603                break;
    604            if (addr) {
    605                addr = calc_reloc(addr, libinfo, id, 0);
    606                if (addr == RELOC_FAILED)
    607                    return -ENOEXEC;
    608                if (put_user_ual(addr, rp))
    609                    return -EFAULT;
    610            }
    611            rp += sizeof(abi_ulong);
    612        }
    613    }
    614
    615    /*
    616     * Now run through the relocation entries.
    617     * We've got to be careful here as C++ produces relocatable zero
    618     * entries in the constructor and destructor tables which are then
    619     * tested for being not zero (which will always occur unless we're
    620     * based from address zero).  This causes an endless loop as __start
    621     * is at zero.  The solution used is to not relocate zero addresses.
    622     * This has the negative side effect of not allowing a global data
    623     * reference to be statically initialised to _stext (I've moved
    624     * __start to address 4 so that is okay).
    625     */
    626    if (rev > OLD_FLAT_VERSION) {
    627        abi_ulong persistent = 0;
    628        for (i = 0; i < relocs; i++) {
    629            abi_ulong addr, relval;
    630
    631            /* Get the address of the pointer to be
    632               relocated (of course, the address has to be
    633               relocated first).  */
    634            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
    635                return -EFAULT;
    636            relval = ntohl(relval);
    637            if (flat_set_persistent(relval, &persistent))
    638                continue;
    639            addr = flat_get_relocate_addr(relval);
    640            rp = calc_reloc(addr, libinfo, id, 1);
    641            if (rp == RELOC_FAILED)
    642                return -ENOEXEC;
    643
    644            /* Get the pointer's value.  */
    645            if (get_user_ual(addr, rp))
    646                return -EFAULT;
    647            addr = flat_get_addr_from_rp(addr, relval, flags, &persistent);
    648            if (addr != 0) {
    649                /*
    650                 * Do the relocation.  PIC relocs in the data section are
    651                 * already in target order
    652                 */
    653                if ((flags & FLAT_FLAG_GOTPIC) == 0)
    654                    addr = ntohl(addr);
    655                addr = calc_reloc(addr, libinfo, id, 0);
    656                if (addr == RELOC_FAILED)
    657                    return -ENOEXEC;
    658
    659                /* Write back the relocated pointer.  */
    660                if (flat_put_addr_at_rp(rp, addr, relval))
    661                    return -EFAULT;
    662            }
    663        }
    664    } else {
    665        for (i = 0; i < relocs; i++) {
    666            abi_ulong relval;
    667            if (get_user_ual(relval, reloc + i * sizeof(abi_ulong)))
    668                return -EFAULT;
    669            old_reloc(&libinfo[0], relval);
    670        }
    671    }
    672
    673    /* zero the BSS.  */
    674    memset(g2h_untagged(datapos + data_len), 0, bss_len);
    675
    676    return 0;
    677}
    678
    679
    680/****************************************************************************/
    681#ifdef CONFIG_BINFMT_SHARED_FLAT
    682
    683/*
    684 * Load a shared library into memory.  The library gets its own data
    685 * segment (including bss) but not argv/argc/environ.
    686 */
    687
    688static int load_flat_shared_library(int id, struct lib_info *libs)
    689{
    690	struct linux_binprm bprm;
    691	int res;
    692	char buf[16];
    693
    694	/* Create the file name */
    695	sprintf(buf, "/lib/lib%d.so", id);
    696
    697	/* Open the file up */
    698	bprm.filename = buf;
    699	bprm.file = open_exec(bprm.filename);
    700	res = PTR_ERR(bprm.file);
    701	if (IS_ERR(bprm.file))
    702		return res;
    703
    704	res = prepare_binprm(&bprm);
    705
    706        if (!is_error(res)) {
    707		res = load_flat_file(&bprm, libs, id, NULL);
    708        }
    709	if (bprm.file) {
    710		allow_write_access(bprm.file);
    711		fput(bprm.file);
    712		bprm.file = NULL;
    713	}
    714	return(res);
    715}
    716
    717#endif /* CONFIG_BINFMT_SHARED_FLAT */
    718
    719int load_flt_binary(struct linux_binprm *bprm, struct image_info *info)
    720{
    721    struct lib_info libinfo[MAX_SHARED_LIBS];
    722    abi_ulong p;
    723    abi_ulong stack_len;
    724    abi_ulong start_addr;
    725    abi_ulong sp;
    726    int res;
    727    int i, j;
    728
    729    memset(libinfo, 0, sizeof(libinfo));
    730    /*
    731     * We have to add the size of our arguments to our stack size
    732     * otherwise it's too easy for users to create stack overflows
    733     * by passing in a huge argument list.  And yes,  we have to be
    734     * pedantic and include space for the argv/envp array as it may have
    735     * a lot of entries.
    736     */
    737    stack_len = 0;
    738    for (i = 0; i < bprm->argc; ++i) {
    739        /* the argv strings */
    740        stack_len += strlen(bprm->argv[i]);
    741    }
    742    for (i = 0; i < bprm->envc; ++i) {
    743        /* the envp strings */
    744        stack_len += strlen(bprm->envp[i]);
    745    }
    746    stack_len += (bprm->argc + 1) * 4; /* the argv array */
    747    stack_len += (bprm->envc + 1) * 4; /* the envp array */
    748
    749
    750    res = load_flat_file(bprm, libinfo, 0, &stack_len);
    751    if (is_error(res)) {
    752            return res;
    753    }
    754
    755    /* Update data segment pointers for all libraries */
    756    for (i=0; i<MAX_SHARED_LIBS; i++) {
    757        if (libinfo[i].loaded) {
    758            abi_ulong p;
    759            p = libinfo[i].start_data;
    760            for (j=0; j<MAX_SHARED_LIBS; j++) {
    761                p -= 4;
    762                /* FIXME - handle put_user() failures */
    763                if (put_user_ual(libinfo[j].loaded
    764                                 ? libinfo[j].start_data
    765                                 : UNLOADED_LIB,
    766                                 p))
    767                    return -EFAULT;
    768            }
    769        }
    770    }
    771
    772    p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4;
    773    DBG_FLT("p=%x\n", (int)p);
    774
    775    /* Copy argv/envp.  */
    776    p = copy_strings(p, bprm->envc, bprm->envp);
    777    p = copy_strings(p, bprm->argc, bprm->argv);
    778    /* Align stack.  */
    779    sp = p & ~(abi_ulong)(sizeof(abi_ulong) - 1);
    780    /* Enforce final stack alignment of 16 bytes.  This is sufficient
    781       for all current targets, and excess alignment is harmless.  */
    782    stack_len = bprm->envc + bprm->argc + 2;
    783    stack_len += flat_argvp_envp_on_stack() ? 2 : 0; /* arvg, argp */
    784    stack_len += 1; /* argc */
    785    stack_len *= sizeof(abi_ulong);
    786    sp -= (sp - stack_len) & 15;
    787    sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p,
    788                             flat_argvp_envp_on_stack());
    789
    790    /* Fake some return addresses to ensure the call chain will
    791     * initialise library in order for us.  We are required to call
    792     * lib 1 first, then 2, ... and finally the main program (id 0).
    793     */
    794    start_addr = libinfo[0].entry;
    795
    796#ifdef CONFIG_BINFMT_SHARED_FLAT
    797#error here
    798    for (i = MAX_SHARED_LIBS-1; i>0; i--) {
    799            if (libinfo[i].loaded) {
    800                    /* Push previous first to call address */
    801                    --sp;
    802                    if (put_user_ual(start_addr, sp))
    803                        return -EFAULT;
    804                    start_addr = libinfo[i].entry;
    805            }
    806    }
    807#endif
    808
    809    /* Stash our initial stack pointer into the mm structure */
    810    info->start_code = libinfo[0].start_code;
    811    info->end_code = libinfo[0].start_code = libinfo[0].text_len;
    812    info->start_data = libinfo[0].start_data;
    813    info->end_data = libinfo[0].end_data;
    814    info->start_brk = libinfo[0].start_brk;
    815    info->start_stack = sp;
    816    info->stack_limit = libinfo[0].start_brk;
    817    info->entry = start_addr;
    818    info->code_offset = info->start_code;
    819    info->data_offset = info->start_data - libinfo[0].text_len;
    820
    821    DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
    822            (int)info->entry, (int)info->start_stack);
    823
    824    return 0;
    825}