diff options
Diffstat (limited to 'sim/rx/load.c')
-rw-r--r-- | sim/rx/load.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/sim/rx/load.c b/sim/rx/load.c new file mode 100644 index 00000000000..4b723744abd --- /dev/null +++ b/sim/rx/load.c @@ -0,0 +1,148 @@ +/* load.c --- loading object files into the RX simulator. + +Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc. +Contributed by Red Hat, Inc. + +This file is part of the GNU simulators. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, see <http://www.gnu.org/licenses/>. */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "bfd.h" +#include "libbfd.h" +#include "cpu.h" +#include "mem.h" +#include "elf/internal.h" +#include "elf/common.h" + +/* A note about endianness and swapping... + + The RX chip is CISC-like in that the opcodes are variable length + and are read as a stream of bytes. However, the chip itself shares + the code prefetch block with the data fetch block, so when it's + configured for big endian mode, the memory fetched for opcodes is + word-swapped. To compensate for this, the ELF file has the code + sections pre-swapped. Our BFD knows this, and for the convenience + of all the other tools, hides this swapping at a very low level. + I.e. it swaps words on the way out and on the way back in. + + Fortunately the iovector routines are unaffected by this, so we + can use them to read in the segments directly, without having + to worry about byte swapping anything. + + However, our opcode decoder and disassemblers need to swap the data + after reading it from the chip memory, just like the chip does. + All in all, the code words are swapped four times between the + assembler and our decoder. + + If the chip is running in little-endian mode, no swapping is done + anywhere. Note also that the *operands* within opcodes are always + encoded in little-endian format. */ + +void +rx_load (bfd *prog) +{ + unsigned long highest_addr_loaded = 0; + Elf_Internal_Phdr * phdrs; + long sizeof_phdrs; + int num_headers; + int i; + + rx_big_endian = bfd_big_endian (prog); + + /* Note we load by ELF program header not by BFD sections. + This is because BFD sections get their information from + the ELF section structure, which only includes a VMA value + and not an LMA value. */ + sizeof_phdrs = bfd_get_elf_phdr_upper_bound (prog); + if (sizeof_phdrs == 0) + { + fprintf (stderr, "Failed to get size of program headers\n"); + return; + } + phdrs = malloc (sizeof_phdrs); + if (phdrs == NULL) + { + fprintf (stderr, "Failed allocate memory to hold program headers\n"); + return; + } + num_headers = bfd_get_elf_phdrs (prog, phdrs); + if (num_headers < 1) + { + fprintf (stderr, "Failed to read program headers\n"); + return; + } + + for (i = 0; i < num_headers; i++) + { + Elf_Internal_Phdr * p = phdrs + i; + char *buf; + bfd_vma size; + bfd_vma base; + file_ptr offset; + + size = p->p_filesz; + if (size <= 0) + continue; + + base = p->p_paddr; + if (verbose > 1) + fprintf (stderr, "[load segment: lma=%08x vma=%08x size=%08x]\n", + (int) base, (int) p->p_vaddr, (int) size); + + buf = malloc (size); + if (buf == NULL) + { + fprintf (stderr, "Failed to allocate buffer to hold program segment\n"); + continue; + } + + offset = p->p_offset; + if (prog->iovec->bseek (prog, offset, SEEK_SET) != 0) + { + fprintf (stderr, "Failed to seek to offset %lx\n", (long) offset); + continue; + } + if (prog->iovec->bread (prog, buf, size) != size) + { + fprintf (stderr, "Failed to read %lx bytes\n", size); + continue; + } + + mem_put_blk (base, buf, size); + free (buf); + if (highest_addr_loaded < base + size - 1 && size >= 4) + highest_addr_loaded = base + size - 1; + } + + free (phdrs); + + regs.r_pc = prog->start_address; + + if (strcmp (bfd_get_target (prog), "srec") == 0 + || regs.r_pc == 0) + { + regs.r_pc = mem_get_si (0xfffffffc); + heaptop = heapbottom = 0; + } + + if (verbose > 1) + fprintf (stderr, "[start pc=%08x %s]\n", + (unsigned int) regs.r_pc, + rx_big_endian ? "BE" : "LE"); +} |