95 |
#define swabls(x) swab64s(x) |
#define swabls(x) swab64s(x) |
96 |
#endif |
#endif |
97 |
|
|
98 |
|
#ifdef ELF_USES_RELOCA |
99 |
|
#define SHT_RELOC SHT_RELA |
100 |
|
#else |
101 |
|
#define SHT_RELOC SHT_REL |
102 |
|
#endif |
103 |
|
|
104 |
#include "thunk.h" |
#include "thunk.h" |
105 |
|
|
106 |
/* all dynamically generated functions begin with this code */ |
/* all dynamically generated functions begin with this code */ |
176 |
swabls(&h->p_align); /* Segment alignment */ |
swabls(&h->p_align); /* Segment alignment */ |
177 |
} |
} |
178 |
|
|
179 |
|
void elf_swap_rel(ELF_RELOC *rel) |
180 |
|
{ |
181 |
|
swabls(&rel->r_offset); |
182 |
|
swabls(&rel->r_info); |
183 |
|
#ifdef ELF_USES_RELOCA |
184 |
|
swabls(&rel->r_addend); |
185 |
|
#endif |
186 |
|
} |
187 |
|
|
188 |
/* ELF file info */ |
/* ELF file info */ |
189 |
int do_swap; |
int do_swap; |
190 |
struct elf_shdr *shdr; |
struct elf_shdr *shdr; |
191 |
|
uint8_t **sdata; |
192 |
struct elfhdr ehdr; |
struct elfhdr ehdr; |
193 |
ElfW(Sym) *symtab; |
ElfW(Sym) *symtab; |
194 |
int nb_syms; |
int nb_syms; |
195 |
char *strtab; |
char *strtab; |
196 |
/* data section */ |
int text_shndx; |
|
uint8_t *data_data, *sdata_data; |
|
|
int data_shndx, sdata_shndx; |
|
197 |
|
|
198 |
uint16_t get16(uint16_t *p) |
uint16_t get16(uint16_t *p) |
199 |
{ |
{ |
257 |
return NULL; |
return NULL; |
258 |
} |
} |
259 |
|
|
260 |
|
int find_reloc(int sh_index) |
261 |
|
{ |
262 |
|
struct elf_shdr *sec; |
263 |
|
int i; |
264 |
|
|
265 |
|
for(i = 0; i < ehdr.e_shnum; i++) { |
266 |
|
sec = &shdr[i]; |
267 |
|
if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) |
268 |
|
return i; |
269 |
|
} |
270 |
|
return 0; |
271 |
|
} |
272 |
|
|
273 |
void *load_data(int fd, long offset, unsigned int size) |
void *load_data(int fd, long offset, unsigned int size) |
274 |
{ |
{ |
275 |
char *data; |
char *data; |
305 |
|
|
306 |
/* generate op code */ |
/* generate op code */ |
307 |
void gen_code(const char *name, host_ulong offset, host_ulong size, |
void gen_code(const char *name, host_ulong offset, host_ulong size, |
308 |
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, int reloc_sh_type, |
FILE *outfile, uint8_t *text, ELF_RELOC *relocs, int nb_relocs, |
309 |
int gen_switch) |
int gen_switch) |
310 |
{ |
{ |
311 |
int copy_size = 0; |
int copy_size = 0; |
527 |
sym_name = strtab + sym->st_name; |
sym_name = strtab + sym->st_name; |
528 |
if (strstart(sym_name, "__op_label", &p)) { |
if (strstart(sym_name, "__op_label", &p)) { |
529 |
uint8_t *ptr; |
uint8_t *ptr; |
530 |
|
int addend; |
531 |
|
unsigned long offset; |
532 |
|
|
533 |
/* test if the variable refers to a label inside |
/* test if the variable refers to a label inside |
534 |
the code we are generating */ |
the code we are generating */ |
535 |
if (sym->st_shndx == data_shndx) |
ptr = sdata[sym->st_shndx]; |
536 |
ptr = data_data; |
if (!ptr) |
537 |
else if (sym->st_shndx == sdata_shndx) |
error("__op_labelN in invalid section"); |
538 |
ptr = sdata_data; |
offset = sym->st_value; |
539 |
else |
addend = 0; |
540 |
error("__op_labelN symbols must be in .data or .sdata section"); |
#ifdef ELF_USES_RELOCA |
541 |
val = *(target_ulong *)(ptr + sym->st_value); |
{ |
542 |
|
int reloc_shndx, nb_relocs1, j; |
543 |
|
|
544 |
|
/* try to find a matching relocation */ |
545 |
|
reloc_shndx = find_reloc(sym->st_shndx); |
546 |
|
if (reloc_shndx) { |
547 |
|
nb_relocs1 = shdr[reloc_shndx].sh_size / |
548 |
|
shdr[reloc_shndx].sh_entsize; |
549 |
|
rel = (ELF_RELOC *)sdata[reloc_shndx]; |
550 |
|
for(j = 0; j < nb_relocs1; j++) { |
551 |
|
if (rel->r_offset == offset) { |
552 |
|
addend = rel->r_addend; |
553 |
|
break; |
554 |
|
} |
555 |
|
rel++; |
556 |
|
} |
557 |
|
} |
558 |
|
} |
559 |
|
#endif |
560 |
|
val = *(target_ulong *)(ptr + offset); |
561 |
|
val += addend; |
562 |
|
|
563 |
if (val >= start_offset && val < start_offset + copy_size) { |
if (val >= start_offset && val < start_offset + copy_size) { |
564 |
n = strtol(p, NULL, 10); |
n = strtol(p, NULL, 10); |
565 |
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); |
fprintf(outfile, " label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset); |
936 |
ElfW(Sym) *sym; |
ElfW(Sym) *sym; |
937 |
char *shstr; |
char *shstr; |
938 |
uint8_t *text; |
uint8_t *text; |
939 |
void *relocs; |
ELF_RELOC *relocs; |
940 |
int nb_relocs, reloc_sh_type; |
int nb_relocs; |
941 |
|
ELF_RELOC *rel; |
942 |
|
|
943 |
fd = open(filename, O_RDONLY); |
fd = open(filename, O_RDONLY); |
944 |
if (fd < 0) |
if (fd < 0) |
977 |
} |
} |
978 |
} |
} |
979 |
|
|
980 |
|
/* read all section data */ |
981 |
|
sdata = malloc(sizeof(void *) * ehdr.e_shnum); |
982 |
|
memset(sdata, 0, sizeof(void *) * ehdr.e_shnum); |
983 |
|
|
984 |
|
for(i = 0;i < ehdr.e_shnum; i++) { |
985 |
|
sec = &shdr[i]; |
986 |
|
if (sec->sh_type != SHT_NOBITS) |
987 |
|
sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size); |
988 |
|
} |
989 |
|
|
990 |
sec = &shdr[ehdr.e_shstrndx]; |
sec = &shdr[ehdr.e_shstrndx]; |
991 |
shstr = load_data(fd, sec->sh_offset, sec->sh_size); |
shstr = sdata[ehdr.e_shstrndx]; |
992 |
|
|
993 |
|
/* swap relocations */ |
994 |
|
for(i = 0; i < ehdr.e_shnum; i++) { |
995 |
|
sec = &shdr[i]; |
996 |
|
if (sec->sh_type == SHT_RELOC) { |
997 |
|
nb_relocs = sec->sh_size / sec->sh_entsize; |
998 |
|
if (do_swap) { |
999 |
|
for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++) |
1000 |
|
elf_swap_rel(rel); |
1001 |
|
} |
1002 |
|
} |
1003 |
|
} |
1004 |
/* text section */ |
/* text section */ |
1005 |
|
|
1006 |
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); |
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text"); |
1007 |
if (!text_sec) |
if (!text_sec) |
1008 |
error("could not find .text section"); |
error("could not find .text section"); |
1009 |
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size); |
text_shndx = text_sec - shdr; |
1010 |
|
text = sdata[text_shndx]; |
1011 |
|
|
|
data_shndx = -1; |
|
|
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".data"); |
|
|
if (sec) { |
|
|
data_shndx = sec - shdr; |
|
|
data_data = load_data(fd, sec->sh_offset, sec->sh_size); |
|
|
} |
|
|
sdata_shndx = -1; |
|
|
sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".sdata"); |
|
|
if (sec) { |
|
|
sdata_shndx = sec - shdr; |
|
|
sdata_data = load_data(fd, sec->sh_offset, sec->sh_size); |
|
|
} |
|
|
|
|
1012 |
/* find text relocations, if any */ |
/* find text relocations, if any */ |
|
nb_relocs = 0; |
|
1013 |
relocs = NULL; |
relocs = NULL; |
1014 |
reloc_sh_type = 0; |
nb_relocs = 0; |
1015 |
for(i = 0; i < ehdr.e_shnum; i++) { |
i = find_reloc(text_shndx); |
1016 |
sec = &shdr[i]; |
if (i != 0) { |
1017 |
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) && |
relocs = (ELF_RELOC *)sdata[i]; |
1018 |
sec->sh_info == (text_sec - shdr)) { |
nb_relocs = shdr[i].sh_size / shdr[i].sh_entsize; |
|
reloc_sh_type = sec->sh_type; |
|
|
relocs = load_data(fd, sec->sh_offset, sec->sh_size); |
|
|
nb_relocs = sec->sh_size / sec->sh_entsize; |
|
|
if (do_swap) { |
|
|
if (sec->sh_type == SHT_REL) { |
|
|
ElfW(Rel) *rel = relocs; |
|
|
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { |
|
|
swabls(&rel->r_offset); |
|
|
swabls(&rel->r_info); |
|
|
} |
|
|
} else { |
|
|
ElfW(Rela) *rel = relocs; |
|
|
for(j = 0, rel = relocs; j < nb_relocs; j++, rel++) { |
|
|
swabls(&rel->r_offset); |
|
|
swabls(&rel->r_info); |
|
|
swabls(&rel->r_addend); |
|
|
} |
|
|
} |
|
|
} |
|
|
break; |
|
|
} |
|
1019 |
} |
} |
1020 |
|
|
1021 |
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); |
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab"); |
1023 |
error("could not find .symtab section"); |
error("could not find .symtab section"); |
1024 |
strtab_sec = &shdr[symtab_sec->sh_link]; |
strtab_sec = &shdr[symtab_sec->sh_link]; |
1025 |
|
|
1026 |
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size); |
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; |
1027 |
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size); |
strtab = sdata[symtab_sec->sh_link]; |
1028 |
|
|
1029 |
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); |
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); |
1030 |
if (do_swap) { |
if (do_swap) { |
1043 |
name = strtab + sym->st_name; |
name = strtab + sym->st_name; |
1044 |
if (strstart(name, OP_PREFIX, &p)) { |
if (strstart(name, OP_PREFIX, &p)) { |
1045 |
gen_code(name, sym->st_value, sym->st_size, outfile, |
gen_code(name, sym->st_value, sym->st_size, outfile, |
1046 |
text, relocs, nb_relocs, reloc_sh_type, 2); |
text, relocs, nb_relocs, 2); |
1047 |
} |
} |
1048 |
} |
} |
1049 |
} else { |
} else { |
1109 |
if (sym->st_shndx != (text_sec - shdr)) |
if (sym->st_shndx != (text_sec - shdr)) |
1110 |
error("invalid section for opcode (0x%x)", sym->st_shndx); |
error("invalid section for opcode (0x%x)", sym->st_shndx); |
1111 |
gen_code(name, sym->st_value, sym->st_size, outfile, |
gen_code(name, sym->st_value, sym->st_size, outfile, |
1112 |
text, relocs, nb_relocs, reloc_sh_type, 1); |
text, relocs, nb_relocs, 1); |
1113 |
} |
} |
1114 |
} |
} |
1115 |
|
|
1164 |
if (sym->st_shndx != (text_sec - shdr)) |
if (sym->st_shndx != (text_sec - shdr)) |
1165 |
error("invalid section for opcode (0x%x)", sym->st_shndx); |
error("invalid section for opcode (0x%x)", sym->st_shndx); |
1166 |
gen_code(name, sym->st_value, sym->st_size, outfile, |
gen_code(name, sym->st_value, sym->st_size, outfile, |
1167 |
text, relocs, nb_relocs, reloc_sh_type, 0); |
text, relocs, nb_relocs, 0); |
1168 |
} |
} |
1169 |
} |
} |
1170 |
} |
} |