/* load.c --- loading object files into the RL78 simulator.
Copyright (C) 2005-2023 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 .
*/
/* This must come before any other includes. */
#include "defs.h"
#include
#include
#include
#include "libiberty.h"
#include "bfd.h"
#include "elf-bfd.h"
#include "elf/rl78.h"
#include "cpu.h"
#include "mem.h"
#include "load.h"
#include "elf/internal.h"
#include "elf/common.h"
/* Helper function for invoking a GDB-specified printf. */
static void
xprintf (host_callback *callback, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
(*callback->vprintf_filtered) (callback, fmt, ap);
va_end (ap);
}
/* Given a file offset, look up the section name. */
static const char *
find_section_name_by_offset (bfd *abfd, file_ptr filepos)
{
asection *s;
for (s = abfd->sections; s; s = s->next)
if (s->filepos == filepos)
return bfd_section_name (s);
return "(unknown)";
}
void
rl78_load (bfd *prog, host_callback *callbacks, const char * const simname)
{
Elf_Internal_Phdr * phdrs;
long sizeof_phdrs;
int num_headers;
int i;
int max_rom = 0;
init_cpu ();
/* 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, "%s: Failed to get size of program headers\n", simname);
return;
}
phdrs = xmalloc (sizeof_phdrs);
num_headers = bfd_get_elf_phdrs (prog, phdrs);
if (num_headers < 1)
{
fprintf (stderr, "%s: Failed to read program headers\n", simname);
return;
}
switch (elf_elfheader (prog)->e_flags & E_FLAG_RL78_CPU_MASK)
{
case E_FLAG_RL78_G10:
rl78_g10_mode = 1;
g13_multiply = 0;
g14_multiply = 0;
mem_set_mirror (0, 0xf8000, 4096);
break;
case E_FLAG_RL78_G13:
rl78_g10_mode = 0;
g13_multiply = 1;
g14_multiply = 0;
break;
case E_FLAG_RL78_G14:
rl78_g10_mode = 0;
g13_multiply = 0;
g14_multiply = 1;
break;
default:
/* Keep whatever was manually specified. */
break;
}
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=%08" PRIx64 " vma=%08" PRIx64 " "
"size=%08" PRIx64 "]\n",
(uint64_t) base, (uint64_t) p->p_vaddr, (uint64_t) size);
if (callbacks)
xprintf (callbacks,
"Loading section %s, size %#" PRIx64 " "
"lma %08" PRIx64 " vma %08" PRIx64 "\n",
find_section_name_by_offset (prog, p->p_offset),
(uint64_t) size, (uint64_t) base, (uint64_t) p->p_vaddr);
buf = xmalloc (size);
offset = p->p_offset;
if (bfd_seek (prog, offset, SEEK_SET) != 0)
{
fprintf (stderr, "%s, Failed to seek to offset %lx\n", simname, (long) offset);
continue;
}
if (bfd_bread (buf, size, prog) != size)
{
fprintf (stderr, "%s: Failed to read %" PRIx64 " bytes\n",
simname, (uint64_t) size);
continue;
}
if (base > 0xeffff || base + size > 0xeffff)
{
fprintf (stderr,
"%s, Can't load image to RAM/SFR space: 0x%" PRIx64 " "
"- 0x%" PRIx64 "\n",
simname, (uint64_t) base, (uint64_t) (base + size));
continue;
}
if (max_rom < base + size)
max_rom = base + size;
mem_put_blk (base, buf, size);
free (buf);
}
free (phdrs);
mem_rom_size (max_rom);
pc = prog->start_address;
if (strcmp (bfd_get_target (prog), "srec") == 0
|| pc == 0)
{
pc = mem_get_hi (0);
}
if (verbose > 1)
fprintf (stderr, "[start pc=%08x]\n", (unsigned int) pc);
}