fixed __op_label handling if RELA relocations are used
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@206 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
95f7652d65
commit
fe31975692
162
dyngen.c
162
dyngen.c
@ -95,6 +95,12 @@ typedef uint64_t host_ulong;
|
|||||||
#define swabls(x) swab64s(x)
|
#define swabls(x) swab64s(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ELF_USES_RELOCA
|
||||||
|
#define SHT_RELOC SHT_RELA
|
||||||
|
#else
|
||||||
|
#define SHT_RELOC SHT_REL
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "thunk.h"
|
#include "thunk.h"
|
||||||
|
|
||||||
/* all dynamically generated functions begin with this code */
|
/* all dynamically generated functions begin with this code */
|
||||||
@ -170,16 +176,24 @@ void elf_swap_phdr(struct elf_phdr *h)
|
|||||||
swabls(&h->p_align); /* Segment alignment */
|
swabls(&h->p_align); /* Segment alignment */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void elf_swap_rel(ELF_RELOC *rel)
|
||||||
|
{
|
||||||
|
swabls(&rel->r_offset);
|
||||||
|
swabls(&rel->r_info);
|
||||||
|
#ifdef ELF_USES_RELOCA
|
||||||
|
swabls(&rel->r_addend);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* ELF file info */
|
/* ELF file info */
|
||||||
int do_swap;
|
int do_swap;
|
||||||
struct elf_shdr *shdr;
|
struct elf_shdr *shdr;
|
||||||
|
uint8_t **sdata;
|
||||||
struct elfhdr ehdr;
|
struct elfhdr ehdr;
|
||||||
ElfW(Sym) *symtab;
|
ElfW(Sym) *symtab;
|
||||||
int nb_syms;
|
int nb_syms;
|
||||||
char *strtab;
|
char *strtab;
|
||||||
/* data section */
|
int text_shndx;
|
||||||
uint8_t *data_data, *sdata_data;
|
|
||||||
int data_shndx, sdata_shndx;
|
|
||||||
|
|
||||||
uint16_t get16(uint16_t *p)
|
uint16_t get16(uint16_t *p)
|
||||||
{
|
{
|
||||||
@ -243,6 +257,19 @@ struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int find_reloc(int sh_index)
|
||||||
|
{
|
||||||
|
struct elf_shdr *sec;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||||
|
sec = &shdr[i];
|
||||||
|
if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void *load_data(int fd, long offset, unsigned int size)
|
void *load_data(int fd, long offset, unsigned int size)
|
||||||
{
|
{
|
||||||
char *data;
|
char *data;
|
||||||
@ -278,7 +305,7 @@ int strstart(const char *str, const char *val, const char **ptr)
|
|||||||
|
|
||||||
/* generate op code */
|
/* generate op code */
|
||||||
void gen_code(const char *name, host_ulong offset, host_ulong size,
|
void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||||
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,
|
||||||
int gen_switch)
|
int gen_switch)
|
||||||
{
|
{
|
||||||
int copy_size = 0;
|
int copy_size = 0;
|
||||||
@ -500,16 +527,39 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||||||
sym_name = strtab + sym->st_name;
|
sym_name = strtab + sym->st_name;
|
||||||
if (strstart(sym_name, "__op_label", &p)) {
|
if (strstart(sym_name, "__op_label", &p)) {
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
int addend;
|
||||||
|
unsigned long offset;
|
||||||
|
|
||||||
/* test if the variable refers to a label inside
|
/* test if the variable refers to a label inside
|
||||||
the code we are generating */
|
the code we are generating */
|
||||||
if (sym->st_shndx == data_shndx)
|
ptr = sdata[sym->st_shndx];
|
||||||
ptr = data_data;
|
if (!ptr)
|
||||||
else if (sym->st_shndx == sdata_shndx)
|
error("__op_labelN in invalid section");
|
||||||
ptr = sdata_data;
|
offset = sym->st_value;
|
||||||
else
|
addend = 0;
|
||||||
error("__op_labelN symbols must be in .data or .sdata section");
|
#ifdef ELF_USES_RELOCA
|
||||||
val = *(target_ulong *)(ptr + sym->st_value);
|
{
|
||||||
|
int reloc_shndx, nb_relocs1, j;
|
||||||
|
|
||||||
|
/* try to find a matching relocation */
|
||||||
|
reloc_shndx = find_reloc(sym->st_shndx);
|
||||||
|
if (reloc_shndx) {
|
||||||
|
nb_relocs1 = shdr[reloc_shndx].sh_size /
|
||||||
|
shdr[reloc_shndx].sh_entsize;
|
||||||
|
rel = (ELF_RELOC *)sdata[reloc_shndx];
|
||||||
|
for(j = 0; j < nb_relocs1; j++) {
|
||||||
|
if (rel->r_offset == offset) {
|
||||||
|
addend = rel->r_addend;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rel++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
val = *(target_ulong *)(ptr + offset);
|
||||||
|
val += addend;
|
||||||
|
|
||||||
if (val >= start_offset && val < start_offset + copy_size) {
|
if (val >= start_offset && val < start_offset + copy_size) {
|
||||||
n = strtol(p, NULL, 10);
|
n = strtol(p, NULL, 10);
|
||||||
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);
|
||||||
@ -886,8 +936,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
|||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
char *shstr;
|
char *shstr;
|
||||||
uint8_t *text;
|
uint8_t *text;
|
||||||
void *relocs;
|
ELF_RELOC *relocs;
|
||||||
int nb_relocs, reloc_sh_type;
|
int nb_relocs;
|
||||||
|
ELF_RELOC *rel;
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY);
|
fd = open(filename, O_RDONLY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -926,58 +977,45 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sec = &shdr[ehdr.e_shstrndx];
|
/* read all section data */
|
||||||
shstr = load_data(fd, sec->sh_offset, sec->sh_size);
|
sdata = malloc(sizeof(void *) * ehdr.e_shnum);
|
||||||
|
memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
|
||||||
|
|
||||||
|
for(i = 0;i < ehdr.e_shnum; i++) {
|
||||||
|
sec = &shdr[i];
|
||||||
|
if (sec->sh_type != SHT_NOBITS)
|
||||||
|
sdata[i] = load_data(fd, sec->sh_offset, sec->sh_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
sec = &shdr[ehdr.e_shstrndx];
|
||||||
|
shstr = sdata[ehdr.e_shstrndx];
|
||||||
|
|
||||||
|
/* swap relocations */
|
||||||
|
for(i = 0; i < ehdr.e_shnum; i++) {
|
||||||
|
sec = &shdr[i];
|
||||||
|
if (sec->sh_type == SHT_RELOC) {
|
||||||
|
nb_relocs = sec->sh_size / sec->sh_entsize;
|
||||||
|
if (do_swap) {
|
||||||
|
for(j = 0, rel = (ELF_RELOC *)sdata[i]; j < nb_relocs; j++, rel++)
|
||||||
|
elf_swap_rel(rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* text section */
|
/* text section */
|
||||||
|
|
||||||
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
|
text_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".text");
|
||||||
if (!text_sec)
|
if (!text_sec)
|
||||||
error("could not find .text section");
|
error("could not find .text section");
|
||||||
text = load_data(fd, text_sec->sh_offset, text_sec->sh_size);
|
text_shndx = text_sec - shdr;
|
||||||
|
text = sdata[text_shndx];
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find text relocations, if any */
|
/* find text relocations, if any */
|
||||||
nb_relocs = 0;
|
|
||||||
relocs = NULL;
|
relocs = NULL;
|
||||||
reloc_sh_type = 0;
|
nb_relocs = 0;
|
||||||
for(i = 0; i < ehdr.e_shnum; i++) {
|
i = find_reloc(text_shndx);
|
||||||
sec = &shdr[i];
|
if (i != 0) {
|
||||||
if ((sec->sh_type == SHT_REL || sec->sh_type == SHT_RELA) &&
|
relocs = (ELF_RELOC *)sdata[i];
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
|
symtab_sec = find_elf_section(shdr, ehdr.e_shnum, shstr, ".symtab");
|
||||||
@ -985,8 +1023,8 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
|||||||
error("could not find .symtab section");
|
error("could not find .symtab section");
|
||||||
strtab_sec = &shdr[symtab_sec->sh_link];
|
strtab_sec = &shdr[symtab_sec->sh_link];
|
||||||
|
|
||||||
symtab = load_data(fd, symtab_sec->sh_offset, symtab_sec->sh_size);
|
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
|
||||||
strtab = load_data(fd, strtab_sec->sh_offset, strtab_sec->sh_size);
|
strtab = sdata[symtab_sec->sh_link];
|
||||||
|
|
||||||
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
|
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
|
||||||
if (do_swap) {
|
if (do_swap) {
|
||||||
@ -1005,7 +1043,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
|||||||
name = strtab + sym->st_name;
|
name = strtab + sym->st_name;
|
||||||
if (strstart(name, OP_PREFIX, &p)) {
|
if (strstart(name, OP_PREFIX, &p)) {
|
||||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||||
text, relocs, nb_relocs, reloc_sh_type, 2);
|
text, relocs, nb_relocs, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1071,7 +1109,7 @@ fprintf(outfile,
|
|||||||
if (sym->st_shndx != (text_sec - shdr))
|
if (sym->st_shndx != (text_sec - shdr))
|
||||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||||
text, relocs, nb_relocs, reloc_sh_type, 1);
|
text, relocs, nb_relocs, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1126,7 +1164,7 @@ fprintf(outfile,
|
|||||||
if (sym->st_shndx != (text_sec - shdr))
|
if (sym->st_shndx != (text_sec - shdr))
|
||||||
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
error("invalid section for opcode (0x%x)", sym->st_shndx);
|
||||||
gen_code(name, sym->st_value, sym->st_size, outfile,
|
gen_code(name, sym->st_value, sym->st_size, outfile,
|
||||||
text, relocs, nb_relocs, reloc_sh_type, 0);
|
text, relocs, nb_relocs, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user