1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: file.c,v 1.119 2005/11/19 21:00:59 debug Exp $ |
* $Id: file.c,v 1.131 2006/03/30 19:36:03 debug Exp $ |
29 |
* |
* |
30 |
* This file contains functions which load executable images into (emulated) |
* This file contains functions which load executable images into (emulated) |
31 |
* memory. File formats recognized so far are: |
* memory. File formats recognized so far are: |
56 |
#include "symbol.h" |
#include "symbol.h" |
57 |
|
|
58 |
|
|
59 |
|
extern int quiet_mode; |
60 |
|
extern int verbose; |
61 |
|
|
62 |
|
|
63 |
/* ELF machine types as strings: (same as exec_elf.h) */ |
/* ELF machine types as strings: (same as exec_elf.h) */ |
64 |
#define N_ELF_MACHINE_TYPES 64 |
#define N_ELF_MACHINE_TYPES 84 |
65 |
static char *elf_machine_type[N_ELF_MACHINE_TYPES] = { |
static char *elf_machine_type[N_ELF_MACHINE_TYPES] = { |
66 |
"NONE", "M32", "SPARC", "386", /* 0..3 */ |
"NONE", "M32", "SPARC", "386", /* 0..3 */ |
67 |
"68K", "88K", "486", "860", /* 4..7 */ |
"68K", "88K", "486", "860", /* 4..7 */ |
78 |
"H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ |
"H8S", "H8_500", "IA_64", "MIPS_X", /* 48..51 */ |
79 |
"COLDFIRE", "68HC12", "unknown54", "unknown55", /* 52..55 */ |
"COLDFIRE", "68HC12", "unknown54", "unknown55", /* 52..55 */ |
80 |
"unknown56", "unknown57", "unknown58", "unknown59", /* 56..59 */ |
"unknown56", "unknown57", "unknown58", "unknown59", /* 56..59 */ |
81 |
"unknown60", "unknown61", "AMD64", "unknown63" /* 60..63 */ |
"unknown60", "unknown61", "AMD64", "unknown63", /* 60..63 */ |
82 |
|
"unknown64", "unknown65", "unknown66", "unknown67", /* 64..67 */ |
83 |
|
"unknown68", "unknown69", "unknown70", "unknown71", /* 68..71 */ |
84 |
|
"unknown72", "unknown73", "unknown74", "unknown75", /* 72..75 */ |
85 |
|
"unknown76", "unknown77", "unknown78", "unknown79", /* 76..79 */ |
86 |
|
"unknown80", "unknown81", "unknown82", "AVR" /* 80..83 */ |
87 |
}; |
}; |
88 |
|
|
89 |
|
|
136 |
#define AOUT_FLAG_DECOSF1 1 |
#define AOUT_FLAG_DECOSF1 1 |
137 |
#define AOUT_FLAG_FROM_BEGINNING 2 |
#define AOUT_FLAG_FROM_BEGINNING 2 |
138 |
#define AOUT_FLAG_VADDR_ZERO_HACK 4 |
#define AOUT_FLAG_VADDR_ZERO_HACK 4 |
139 |
|
#define AOUT_FLAG_NO_SIZES 8 |
140 |
/* |
/* |
141 |
* file_load_aout(): |
* file_load_aout(): |
142 |
* |
* |
172 |
if (flags & AOUT_FLAG_DECOSF1) { |
if (flags & AOUT_FLAG_DECOSF1) { |
173 |
fread(&buf, 1, 32, f); |
fread(&buf, 1, 32, f); |
174 |
vaddr = buf[16] + (buf[17] << 8) + |
vaddr = buf[16] + (buf[17] << 8) + |
175 |
(buf[18] << 16) + (buf[19] << 24); |
(buf[18] << 16) + ((uint64_t)buf[19] << 24); |
176 |
entry = buf[20] + (buf[21] << 8) + |
entry = buf[20] + (buf[21] << 8) + |
177 |
(buf[22] << 16) + (buf[23] << 24); |
(buf[22] << 16) + ((uint64_t)buf[23] << 24); |
178 |
debug("OSF1 a.out, load address 0x%08lx, " |
debug("OSF1 a.out, load address 0x%08lx, " |
179 |
"entry point 0x%08x\n", (long)vaddr, (long)entry); |
"entry point 0x%08x\n", (long)vaddr, (long)entry); |
180 |
symbsize = 0; |
symbsize = 0; |
183 |
textsize = ftello(f) - 512; |
textsize = ftello(f) - 512; |
184 |
datasize = 0; |
datasize = 0; |
185 |
fseek(f, 512, SEEK_SET); |
fseek(f, 512, SEEK_SET); |
186 |
|
} else if (flags & AOUT_FLAG_NO_SIZES) { |
187 |
|
fseek(f, 0, SEEK_END); |
188 |
|
textsize = ftello(f) - 32; |
189 |
|
datasize = 0; |
190 |
|
vaddr = entry = 0; |
191 |
|
fseek(f, 32, SEEK_SET); |
192 |
} else { |
} else { |
193 |
len = fread(&aout_header, 1, sizeof(aout_header), f); |
len = fread(&aout_header, 1, sizeof(aout_header), f); |
194 |
if (len != sizeof(aout_header)) { |
if (len != sizeof(aout_header)) { |
347 |
char *symbols, *strings; |
char *symbols, *strings; |
348 |
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
uint32_t cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; |
349 |
uint64_t vmaddr, vmsize, fileoff, filesize; |
uint64_t vmaddr, vmsize, fileoff, filesize; |
350 |
int cmd_type, cmd_len, pos, i, flavor; |
int cmd_type, cmd_len, i, flavor; |
351 |
int32_t symoff, nsyms, stroff, strsize; |
int32_t symoff, nsyms, stroff, strsize; |
352 |
size_t len; |
size_t len, pos; |
353 |
|
|
354 |
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
if (m->cpus[0]->byte_order == EMUL_BIG_ENDIAN) |
355 |
encoding = ELFDATA2MSB; |
encoding = ELFDATA2MSB; |
874 |
debug("%c", sym->name[i]); */ |
debug("%c", sym->name[i]); */ |
875 |
v = sym->value[0] + (sym->value[1] << 8) |
v = sym->value[0] + (sym->value[1] << 8) |
876 |
+ (sym->value[2] << 16) |
+ (sym->value[2] << 16) |
877 |
+ (sym->value[3] << 24); |
+ ((uint64_t)sym->value[3] << 24); |
878 |
altname = sym->name[4] + (sym->name[5] << 8) |
altname = sym->name[4] + (sym->name[5] << 8) |
879 |
+ (sym->name[6] << 16) |
+ (sym->name[6] << 16) |
880 |
+ (sym->name[3] << 24); |
+ ((uint64_t)sym->name[3] << 24); |
881 |
t = (sym->type[1] << 8) + sym->type[0]; |
t = (sym->type[1] << 8) + sym->type[0]; |
882 |
/* TODO: big endian COFF? */ |
/* TODO: big endian COFF? */ |
883 |
/* debug("' value=0x%x type=0x%04x", v, t); */ |
/* debug("' value=0x%x type=0x%04x", v, t); */ |
1108 |
bytes[2]; |
bytes[2]; |
1109 |
break; |
break; |
1110 |
case 3: data_start = 4; |
case 3: data_start = 4; |
1111 |
vaddr = (bytes[0] << 24) + (bytes[1] << 16) + |
vaddr = ((uint64_t)bytes[0] << 24) + |
1112 |
(bytes[2] << 8) + bytes[3]; |
(bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; |
1113 |
} |
} |
1114 |
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
m->cpus[0]->memory_rw(m->cpus[0], mem, vaddr, |
1115 |
&bytes[data_start], count - 1 - data_start, |
&bytes[data_start], count - 1 - data_start, |
1121 |
case 9: |
case 9: |
1122 |
/* switch again, to get the entry point: */ |
/* switch again, to get the entry point: */ |
1123 |
switch (buf[1]) { |
switch (buf[1]) { |
1124 |
case 7: entry = (bytes[0] << 24) + (bytes[1] << 16) + |
case 7: entry = ((uint64_t)bytes[0] << 24) + |
1125 |
(bytes[2] << 8) + bytes[3]; |
(bytes[1] << 16) + (bytes[2]<<8) + bytes[3]; |
1126 |
break; |
break; |
1127 |
case 8: entry = (bytes[0] << 16) + (bytes[1] << 8) + |
case 8: entry = (bytes[0] << 16) + (bytes[1] << 8) + |
1128 |
bytes[2]; |
bytes[2]; |
1210 |
vaddr += len; |
vaddr += len; |
1211 |
} |
} |
1212 |
|
|
1213 |
debug("RAW: 0x%llx bytes @ 0x%08llx", |
debug("RAW: 0x%"PRIx64" bytes @ 0x%08"PRIx64, |
1214 |
(long long) (ftello(f) - skip), (long long)loadaddr); |
(uint64_t) (ftello(f) - skip), (uint64_t) loadaddr); |
1215 |
|
|
1216 |
if (skip != 0) |
if (skip != 0) |
1217 |
debug(" (0x%llx bytes of header skipped)", (long long)skip); |
debug(" (0x%"PRIx64" bytes of header skipped)", |
1218 |
|
(uint64_t) skip); |
1219 |
|
|
1220 |
debug("\n"); |
debug("\n"); |
1221 |
|
|
1222 |
fclose(f); |
fclose(f); |
1411 |
} |
} |
1412 |
break; |
break; |
1413 |
case ARCH_MIPS: |
case ARCH_MIPS: |
|
case ARCH_NEWMIPS: |
|
1414 |
switch (emachine) { |
switch (emachine) { |
1415 |
case EM_MIPS: |
case EM_MIPS: |
1416 |
case EM_MIPS_RS3_LE: |
case EM_MIPS_RS3_LE: |
1471 |
encoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)", s); |
encoding == ELFDATA2LSB? "LSB (LE)" : "MSB (BE)", s); |
1472 |
|
|
1473 |
if (elf64) |
if (elf64) |
1474 |
debug("%016llx\n", (long long)eentry); |
debug("%016"PRIx64"\n", (uint64_t) eentry); |
1475 |
else |
else |
1476 |
debug("%08x\n", (int)eentry); |
debug("%08"PRIx32"\n", (uint32_t) eentry); |
|
|
|
|
/* |
|
|
* MIPS16 encoding? |
|
|
* |
|
|
* TODO: Find out what e_flag actually contains. |
|
|
* TODO 2: This only sets mips16 for cpu 0. Yuck. Fix this! |
|
|
*/ |
|
|
if ((arch == ARCH_MIPS || arch == ARCH_NEWMIPS) |
|
|
&& ((eflags >> 24) & 0xff) == 0x24) { |
|
|
debug("MIPS16 encoding (e_flags = 0x%08x)\n", eflags); |
|
|
#ifdef ENABLE_MIPS16 |
|
|
m->cpus[0]->cd.mips.mips16 = 1; |
|
|
#else |
|
|
fatal("ENABLE_MIPS16 must be defined in misc.h.\n" |
|
|
"(or use the --mips16 configure option)\n"); |
|
|
exit(1); |
|
|
#endif |
|
|
} else if ((arch == ARCH_MIPS || arch == ARCH_NEWMIPS) |
|
|
&& (eentry & 0x3)) { |
|
|
debug("MIPS16 encoding (eentry not 32-bit aligned)\n"); |
|
|
#ifdef ENABLE_MIPS16 |
|
|
m->cpus[0]->cd.mips.mips16 = 1; |
|
|
#else |
|
|
fatal("ENABLE_MIPS16 must be defined in misc.h.\n" |
|
|
"(or use the --mips16 configure option)\n"); |
|
|
exit(1); |
|
|
#endif |
|
|
} |
|
1477 |
|
|
1478 |
/* |
/* |
1479 |
* SH64: 32-bit instruction encoding? TODO |
* SH64: 32-bit instruction encoding? TODO |
1521 |
} |
} |
1522 |
|
|
1523 |
/* |
/* |
1524 |
* Hack for loading Linux/PPC kernels, linked to high |
* Hack for loading PPC kernels that are linked to high |
1525 |
* addresses, at low addresses. |
* addresses. (This requires enabling of instruction and |
1526 |
|
* data virtual address translation.) |
1527 |
*/ |
*/ |
1528 |
if (arch == ARCH_PPC) { |
if (arch == ARCH_PPC) { |
1529 |
if (elf64) { |
if ( (elf64 && (p_vaddr >> 60) != 0) || |
1530 |
p_vaddr &= 0x0fffffffffffffffULL; |
(!elf64 && (p_vaddr >> 28) != 0) ) |
1531 |
p_paddr &= 0x0fffffffffffffffULL; |
m->cpus[m->bootstrap_cpu]-> |
1532 |
} else { |
cd.ppc.msr |= PPC_MSR_IR | PPC_MSR_DR; |
|
p_vaddr &= 0x0fffffff; |
|
|
p_paddr &= 0x0fffffff; |
|
|
} |
|
1533 |
} |
} |
1534 |
|
|
1535 |
if (p_memsz != 0 && (p_type == PT_LOAD || |
if (p_memsz != 0 && (p_type == PT_LOAD || |
1538 |
if (p_type == PT_LOAD) |
if (p_type == PT_LOAD) |
1539 |
debug("load"); |
debug("load"); |
1540 |
else |
else |
1541 |
debug("0x%08x", (int)p_type); |
debug("0x%08"PRIx32, (uint32_t) p_type); |
1542 |
|
|
1543 |
debug(") @ 0x%llx, vaddr 0x", (long long)p_offset); |
debug(") @ 0x%"PRIx64", vaddr 0x", (uint64_t) p_offset); |
1544 |
|
|
1545 |
if (elf64) |
if (elf64) |
1546 |
debug("%016llx", (long long)p_vaddr); |
debug("%016"PRIx64, (uint64_t) p_vaddr); |
1547 |
else |
else |
1548 |
debug("%08x", (int)p_vaddr); |
debug("%08"PRIx32, (uint32_t) p_vaddr); |
1549 |
|
|
1550 |
debug(" len=0x%llx\n", (long long)p_memsz); |
debug(" len=0x%"PRIx64"\n", (uint64_t) p_memsz); |
1551 |
|
|
1552 |
if (p_vaddr != p_paddr) |
if (p_vaddr != p_paddr) { |
1553 |
fatal("WARNING! vaddr (0x%llx) and paddr " |
if (elf64) |
1554 |
"(0x%llx) differ; using vaddr\n", |
debug("NOTE: vaddr (0x%"PRIx64") and " |
1555 |
(long long)p_vaddr, (long long)p_paddr); |
"paddr (0x%"PRIx64") differ; using " |
1556 |
|
"vaddr\n", (uint64_t) p_vaddr, |
1557 |
|
(uint64_t) p_paddr); |
1558 |
|
else |
1559 |
|
debug("NOTE: vaddr (0x%08"PRIx32") and " |
1560 |
|
"paddr (0x%08"PRIx32") differ; usin" |
1561 |
|
"g vaddr\n", (uint32_t) p_vaddr, |
1562 |
|
(uint32_t)p_paddr); |
1563 |
|
} |
1564 |
|
|
1565 |
if (p_memsz < p_filesz) { |
if (p_memsz < p_filesz) { |
1566 |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
fprintf(stderr, "%s: memsz < filesz. TODO: how" |
1567 |
" to handle this? memsz=%016llx filesz=" |
" to handle this? memsz=%016"PRIx64 |
1568 |
"%016llx\n", filename, (long long)p_memsz, |
" filesz=%016"PRIx64"\n", filename, |
1569 |
(long long)p_filesz); |
(uint64_t) p_memsz, (uint64_t) p_filesz); |
1570 |
exit(1); |
exit(1); |
1571 |
} |
} |
1572 |
|
|
1634 |
off_t sh_offset; |
off_t sh_offset; |
1635 |
int n_entries; /* for reading the symbol / string tables */ |
int n_entries; /* for reading the symbol / string tables */ |
1636 |
|
|
1637 |
/* debug("section header %i at %016llx\n", i, |
/* debug("section header %i at %016"PRIx64"\n", i, |
1638 |
(long long) eshoff+i*eshentsize); */ |
(uint64_t) eshoff+i*eshentsize); */ |
1639 |
|
|
1640 |
fseek(f, eshoff + i * eshentsize, SEEK_SET); |
fseek(f, eshoff + i * eshentsize, SEEK_SET); |
1641 |
|
|
1721 |
exit(1); |
exit(1); |
1722 |
} |
} |
1723 |
|
|
1724 |
debug("%i symbol entries at 0x%llx\n", |
debug("%i symbol entries at 0x%"PRIx64"\n", |
1725 |
(int)n_entries, (long long)sh_offset); |
(int) n_entries, (uint64_t) sh_offset); |
1726 |
|
|
1727 |
n_symbols = n_entries; |
n_symbols = n_entries; |
1728 |
} |
} |
1755 |
exit(1); |
exit(1); |
1756 |
} |
} |
1757 |
|
|
1758 |
debug("%i bytes of symbol strings at 0x%llx\n", |
debug("%i bytes of symbol strings at 0x%"PRIx64"\n", |
1759 |
(int)sh_size, (long long)sh_offset); |
(int) sh_size, (uint64_t) sh_offset); |
1760 |
|
|
1761 |
symbol_strings[sh_size] = '\0'; |
symbol_strings[sh_size] = '\0'; |
1762 |
symbol_length = sh_size; |
symbol_length = sh_size; |
1785 |
unencode(size, &sym32.st_size, Elf32_Word); |
unencode(size, &sym32.st_size, Elf32_Word); |
1786 |
} |
} |
1787 |
|
|
1788 |
/* debug("symbol info=0x%02x addr=0x%016llx" |
/* debug("symbol info=0x%02x addr=0x%016"PRIx64 |
1789 |
" (%i) '%s'\n", st_info, (long long)addr, |
" (%i) '%s'\n", st_info, (uint64_t) addr, |
1790 |
st_name, symbol_strings + st_name); */ |
st_name, symbol_strings + st_name); */ |
1791 |
|
|
1792 |
if (size == 0) |
if (size == 0) |
1794 |
|
|
1795 |
if (addr != 0) /* && ((st_info >> 4) & 0xf) |
if (addr != 0) /* && ((st_info >> 4) & 0xf) |
1796 |
>= STB_GLOBAL) */ { |
>= STB_GLOBAL) */ { |
1797 |
/* debug("symbol info=0x%02x addr=0x%016llx" |
/* debug("symbol info=0x%02x addr=0x%016"PRIx64 |
1798 |
" '%s'\n", st_info, (long long)addr, |
" '%s'\n", st_info, (uint64_t) addr, |
1799 |
symbol_strings + st_name); */ |
symbol_strings + st_name); */ |
1800 |
add_symbol_name(&m->symbol_context, |
add_symbol_name(&m->symbol_context, |
1801 |
addr, size, symbol_strings + st_name, |
addr, size, symbol_strings + st_name, |
1805 |
if (strcmp(symbol_strings + st_name, "_gp") == 0) { |
if (strcmp(symbol_strings + st_name, "_gp") == 0) { |
1806 |
debug("found _gp address: 0x"); |
debug("found _gp address: 0x"); |
1807 |
if (elf64) |
if (elf64) |
1808 |
debug("%016llx\n", (long long)addr); |
debug("%016"PRIx64"\n", (uint64_t)addr); |
1809 |
else |
else |
1810 |
debug("%08x\n", (int)addr); |
debug("%08"PRIx32"\n", (uint32_t)addr); |
1811 |
*gpp = addr; |
*gpp = addr; |
1812 |
} |
} |
1813 |
} |
} |
1860 |
((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + |
((uint64_t)b[5] << 16) + ((uint64_t)b[6] << 8) + |
1861 |
(uint64_t)b[7]; |
(uint64_t)b[7]; |
1862 |
|
|
1863 |
debug("entrypoint 0x%016llx, toc_base 0x%016llx\n", |
debug("entrypoint 0x%016"PRIx64", toc_base 0x%016"PRIx64"\n", |
1864 |
(long long)*entrypointp, (long long)toc_base); |
(uint64_t) *entrypointp, (uint64_t) toc_base); |
1865 |
if (tocp != NULL) |
if (tocp != NULL) |
1866 |
*tocp = toc_base; |
*tocp = toc_base; |
1867 |
} |
} |
1895 |
char *filename, uint64_t *entrypointp, |
char *filename, uint64_t *entrypointp, |
1896 |
int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp) |
int arch, uint64_t *gpp, int *byte_orderp, uint64_t *tocp) |
1897 |
{ |
{ |
1898 |
int iadd = 4; |
int iadd = DEBUG_INDENTATION, old_quiet_mode; |
1899 |
FILE *f; |
FILE *f; |
1900 |
unsigned char buf[12]; |
unsigned char buf[12]; |
1901 |
unsigned char buf2[2]; |
unsigned char buf2[2]; |
1921 |
if (filename[0] == '@') |
if (filename[0] == '@') |
1922 |
return; |
return; |
1923 |
|
|
1924 |
debug("loading %s:\n", filename); |
debug("loading %s%s\n", filename, verbose >= 2? ":" : ""); |
1925 |
debug_indentation(iadd); |
debug_indentation(iadd); |
1926 |
|
|
1927 |
|
old_quiet_mode = quiet_mode; |
1928 |
|
if (verbose < 2) |
1929 |
|
quiet_mode = 1; |
1930 |
|
|
1931 |
f = fopen(filename, "r"); |
f = fopen(filename, "r"); |
1932 |
if (f == NULL) { |
if (f == NULL) { |
1933 |
file_load_raw(machine, mem, filename, entrypointp); |
file_load_raw(machine, mem, filename, entrypointp); |
1983 |
entrypointp, arch, byte_orderp); |
entrypointp, arch, byte_orderp); |
1984 |
goto ret; |
goto ret; |
1985 |
} |
} |
1986 |
|
if (buf[0]==0x01 && buf[1]==0x03 && buf[2]==0x01 && buf[3]==0x07) { |
1987 |
|
/* SPARC a.out (old 32-bit NetBSD etc) */ |
1988 |
|
file_load_aout(machine, mem, filename, AOUT_FLAG_NO_SIZES, |
1989 |
|
entrypointp, arch, byte_orderp); |
1990 |
|
goto ret; |
1991 |
|
} |
1992 |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
if (buf[0]==0x00 && buf[2]==0x00 && buf[8]==0x7a && buf[9]==0x75) { |
1993 |
/* DEC OSF1 on MIPS: */ |
/* DEC OSF1 on MIPS: */ |
1994 |
file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, |
file_load_aout(machine, mem, filename, AOUT_FLAG_DECOSF1, |
2091 |
|
|
2092 |
ret: |
ret: |
2093 |
debug_indentation(-iadd); |
debug_indentation(-iadd); |
2094 |
|
quiet_mode = old_quiet_mode; |
2095 |
} |
} |
2096 |
|
|