X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=dyngen.c;h=d301c714fc11e7d0b8660586fbeece898b0af8a6;hb=985a03b0ce38275c2ea355bf29b6d6b5779dbb56;hp=c1f348a94fecf96b3099473092219826d7b9f53a;hpb=fd4a43e4e28a594a20beefe78b0fe7ecd34bd981;p=qemu.git diff --git a/dyngen.c b/dyngen.c index c1f348a94..d301c714f 100644 --- a/dyngen.c +++ b/dyngen.c @@ -1,6 +1,6 @@ /* * Generic Dynamic compiler generator - * + * * Copyright (c) 2003 Fabrice Bellard * * The COFF object format support was extracted from Kazu's QEMU port @@ -117,6 +117,21 @@ #define elf_check_arch(x) ((x) == EM_68K) #define ELF_USES_RELOCA +#elif defined(HOST_MIPS) + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_MIPS +#define elf_check_arch(x) ((x) == EM_MIPS) +#define ELF_USES_RELOC + +#elif defined(HOST_MIPS64) + +/* Assume n32 ABI here, which is ELF32. */ +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_MIPS +#define elf_check_arch(x) ((x) == EM_MIPS) +#define ELF_USES_RELOCA + #else #error unsupported CPU - please update the code #endif @@ -127,10 +142,12 @@ typedef int32_t host_long; typedef uint32_t host_ulong; #define swabls(x) swab32s(x) +#define swablss(x) swab32ss(x) #else typedef int64_t host_long; typedef uint64_t host_ulong; #define swabls(x) swab64s(x) +#define swablss(x) swab64ss(x) #endif #ifdef ELF_USES_RELOCA @@ -146,11 +163,11 @@ typedef uint64_t host_ulong; #ifdef CONFIG_FORMAT_COFF -#include "a.out.h" - typedef int32_t host_long; typedef uint32_t host_ulong; +#include "a.out.h" + #define FILENAMELEN 256 typedef struct coff_sym { @@ -187,11 +204,11 @@ typedef uint32_t host_ulong; struct nlist_extended { union { - char *n_name; - long n_strx; + char *n_name; + long n_strx; } n_un; - unsigned char n_type; - unsigned char n_sect; + unsigned char n_type; + unsigned char n_sect; short st_desc; unsigned long st_value; unsigned long st_size; @@ -215,7 +232,7 @@ enum { int do_swap; -void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) +static void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -226,7 +243,7 @@ void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(cons exit(1); } -void *load_data(int fd, long offset, unsigned int size) +static void *load_data(int fd, long offset, unsigned int size) { char *data; @@ -284,11 +301,21 @@ void swab32s(uint32_t *p) *p = bswap32(*p); } +void swab32ss(int32_t *p) +{ + *p = bswap32(*p); +} + void swab64s(uint64_t *p) { *p = bswap64(*p); } +void swab64ss(int64_t *p) +{ + *p = bswap64(*p); +} + uint16_t get16(uint16_t *p) { uint16_t val; @@ -345,10 +372,10 @@ int elf_must_swap(struct elfhdr *h) } swaptest; swaptest.i = 1; - return (h->e_ident[EI_DATA] == ELFDATA2MSB) != + return (h->e_ident[EI_DATA] == ELFDATA2MSB) != (swaptest.b[0] == 0); } - + void elf_swap_ehdr(struct elfhdr *h) { swab16s(&h->e_type); /* Object file type */ @@ -397,11 +424,11 @@ void elf_swap_rel(ELF_RELOC *rel) swabls(&rel->r_offset); swabls(&rel->r_info); #ifdef ELF_USES_RELOCA - swabls(&rel->r_addend); + swablss(&rel->r_addend); #endif } -struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, +struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, const char *name) { int i; @@ -426,7 +453,7 @@ int find_reloc(int sh_index) for(i = 0; i < ehdr.e_shnum; i++) { sec = &shdr[i]; - if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) + if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) return i; } return 0; @@ -456,11 +483,11 @@ int load_object(const char *filename) ElfW(Sym) *sym; char *shstr; ELF_RELOC *rel; - + fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd < 0) error("can't open file '%s'", filename); - + /* Read ELF header. */ if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) error("unable to read file header"); @@ -497,7 +524,7 @@ int load_object(const char *filename) /* read all section data */ 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) @@ -505,7 +532,7 @@ int load_object(const char *filename) } sec = &shdr[ehdr.e_shstrndx]; - shstr = sdata[ehdr.e_shstrndx]; + shstr = (char *)sdata[ehdr.e_shstrndx]; /* swap relocations */ for(i = 0; i < ehdr.e_shnum; i++) { @@ -541,8 +568,8 @@ int load_object(const char *filename) strtab_sec = &shdr[symtab_sec->sh_link]; symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr]; - strtab = sdata[symtab_sec->sh_link]; - + strtab = (char *)sdata[symtab_sec->sh_link]; + nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym)); if (do_swap) { for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { @@ -582,7 +609,7 @@ void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym) { char *q; int c, i, len; - + if (ext_sym->e.e.e_zeroes != 0) { q = sym->st_name; for(i = 0; i < 8; i++) { @@ -616,7 +643,7 @@ char *name_for_dotdata(struct coff_rel *rel) if (sym->st_syment->e_scnum == data_shndx && text_data >= sym->st_value && text_data < sym->st_value + sym->st_size) { - + return sym->st_name; } @@ -674,15 +701,17 @@ int load_object(const char *filename) uint32_t *n_strtab; EXE_SYM *sym; EXE_RELOC *rel; - - fd = open(filename, O_RDONLY + const char *p; + int aux_size, j; + + fd = open(filename, O_RDONLY #ifdef _WIN32 | O_BINARY #endif ); - if (fd < 0) + if (fd < 0) error("can't open file '%s'", filename); - + /* Read COFF header. */ if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr)) error("unable to read file header"); @@ -695,12 +724,11 @@ int load_object(const char *filename) /* read section headers */ shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr)); - + /* read all section data */ sdata = malloc(sizeof(void *) * fhdr.f_nscns); memset(sdata, 0, sizeof(void *) * fhdr.f_nscns); - - const char *p; + for(i = 0;i < fhdr.f_nscns; i++) { sec = &shdr[i]; if (!strstart(sec->s_name, ".bss", &p)) @@ -720,7 +748,7 @@ int load_object(const char *filename) if (!data_sec) error("could not find .data section"); coff_data_shndx = data_sec - shdr; - + coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ); for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) { for(i=0;i<8;i++) @@ -730,8 +758,8 @@ int load_object(const char *filename) n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE); - strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab); - + strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab); + nb_syms = fhdr.f_nsyms; for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) { @@ -744,7 +772,6 @@ int load_object(const char *filename) /* set coff symbol */ symtab = malloc(sizeof(struct coff_sym) * nb_syms); - int aux_size, j; for (i = 0, ext_sym = coff_symtab, sym = symtab; i < nb_syms; i++, ext_sym++, sym++) { memset(sym, 0, sizeof(*sym)); sym->st_syment = ext_sym; @@ -778,12 +805,12 @@ int load_object(const char *filename) } else { sym->st_size = 0; } - + sym->st_type = ext_sym->e_type; sym->st_shndx = ext_sym->e_scnum; } - + /* find text relocations, if any */ sec = &shdr[coff_text_shndx]; coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ); @@ -791,7 +818,7 @@ int load_object(const char *filename) /* set coff relocation */ relocs = malloc(sizeof(struct coff_rel) * nb_relocs); - for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs; + for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs; i++, ext_rel++, rel++) { memset(rel, 0, sizeof(*rel)); rel->r_reloc = ext_rel; @@ -820,7 +847,7 @@ uint8_t **sdata; /* relocs */ struct relocation_info *relocs; - + /* symbols */ EXE_SYM *symtab; struct nlist *symtab_std; @@ -840,10 +867,10 @@ static inline char *find_str_by_index(int index) static char *get_sym_name(EXE_SYM *sym) { char *name = find_str_by_index(sym->n_un.n_strx); - + if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */ return "debug"; - + if(!name) return name; if(name[0]=='_') @@ -853,7 +880,7 @@ static char *get_sym_name(EXE_SYM *sym) } /* find a section index given its segname, sectname */ -static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, +static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, const char *sectname) { int i; @@ -869,7 +896,7 @@ static int find_mach_sec_index(struct section *section_hdr, int shnum, const cha } /* find a section header given its segname, sectname */ -struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, +struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, const char *sectname) { int index = find_mach_sec_index(section_hdr, shnum, segname, sectname); @@ -882,7 +909,7 @@ struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value) { struct scattered_relocation_info * scarel; - + if(R_SCATTERED & rel->r_address) { scarel = (struct scattered_relocation_info*)rel; if(scarel->r_type != PPC_RELOC_PAIR) @@ -899,7 +926,7 @@ static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset ) { int i, ret = -1; - + for( i = 0 ; i < nb_syms; i++ ) { if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) && @@ -918,35 +945,35 @@ static const char * find_sym_with_value_and_sec_number( int value, int sectnum, } } -/* - * Find symbol name given a (virtual) address, and a section which is of type +/* + * Find symbol name given a (virtual) address, and a section which is of type * S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS */ static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr) { unsigned int tocindex, symindex, size; const char *name = 0; - + /* Sanity check */ if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) ) return (char*)0; - + if( sec_hdr->flags & S_SYMBOL_STUBS ){ size = sec_hdr->reserved2; if(size == 0) error("size = 0"); - + } else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS || sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS) size = sizeof(unsigned long); else return 0; - + /* Compute our index in toc */ tocindex = (address - sec_hdr->addr)/size; symindex = tocdylib[sec_hdr->reserved1 + tocindex]; - + name = get_sym_name(&symtab[symindex]); return name; @@ -971,24 +998,24 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) int sectnum = rel->r_symbolnum; int sectoffset; int other_half=0; - + /* init the slide value */ *sslide = 0; - + if(R_SCATTERED & rel->r_address) return (char *)find_reloc_name_given_its_address(sca_rel->r_value); if(rel->r_extern) { /* ignore debug sym */ - if ( symtab[rel->r_symbolnum].n_type & N_STAB ) + if ( symtab[rel->r_symbolnum].n_type & N_STAB ) return 0; return get_sym_name(&symtab[rel->r_symbolnum]); } /* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */ sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff; - + if(sectnum==0xffffff) return 0; @@ -1014,14 +1041,14 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide) if(rel->r_pcrel) sectoffset += rel->r_address; - + if (rel->r_type == PPC_RELOC_BR24) name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, §ion_hdr[sectnum-1]); /* search it in the full symbol list, if not found */ if(!name) name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide); - + return name; } @@ -1053,11 +1080,11 @@ int load_object(const char *filename) unsigned int i, j; EXE_SYM *sym; struct nlist *syment; - + fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd < 0) error("can't open file '%s'", filename); - + /* Read Mach header. */ if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr)) error("unable to read file header"); @@ -1066,13 +1093,13 @@ int load_object(const char *filename) if (!check_mach_header(mach_hdr)) { error("bad Mach header"); } - + if (mach_hdr.cputype != CPU_TYPE_POWERPC) error("Unsupported CPU"); - + if (mach_hdr.filetype != MH_OBJECT) error("Unsupported Mach Object"); - + /* read segment headers */ for(i=0, j=sizeof(mach_hdr); insects); memset(sdata, 0, sizeof(void *) * segment->nsects); - + /* Load the data in section data */ for(i = 0; i < segment->nsects; i++) { sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size); } - + /* text section */ text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT); i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT); if (i == -1 || !text_sec_hdr) error("could not find __TEXT,__text section"); text = sdata[i]; - + /* Make sure dysym was loaded */ if(!(int)dysymtabcmd) error("could not find __DYSYMTAB segment"); - + /* read the table of content of the indirect sym */ tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) ); - + /* Make sure symtab was loaded */ if(!(int)symtabcmd) error("could not find __SYMTAB segment"); @@ -1143,20 +1170,20 @@ int load_object(const char *filename) symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist)); strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize); - + symtab = malloc(sizeof(EXE_SYM) * nb_syms); - + /* Now transform the symtab, to an extended version, with the sym size, and the C name */ for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) { struct nlist *sym_follow, *sym_next = 0; unsigned int j; memset(sym, 0, sizeof(*sym)); - + if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */ continue; - + memcpy(sym, syment, sizeof(*syment)); - + /* Find the following symbol in order to get the current symbol size */ for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) { if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value)) @@ -1174,7 +1201,7 @@ int load_object(const char *filename) else sym->st_size = text_sec_hdr->size - sym->st_value; } - + /* Find Reloc */ relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info)); nb_relocs = text_sec_hdr->nreloc; @@ -1196,7 +1223,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name) } else { #ifdef HOST_SPARC if (sym_name[0] == '.') - snprintf(name, sizeof(name), + snprintf(name, name_size, "(long)(&__dot_%s)", sym_name + 1); else @@ -1255,90 +1282,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, { uint8_t *p; uint32_t insn; - int offset, min_offset, pc_offset, data_size; + int offset, min_offset, pc_offset, data_size, spare, max_pool; uint8_t data_allocated[1024]; unsigned int data_index; - + int type; + memset(data_allocated, 0, sizeof(data_allocated)); - + p = p_start; min_offset = p_end - p_start; + spare = 0x7fffffff; while (p < p_start + min_offset) { insn = get32((uint32_t *)p); + /* TODO: Armv5e ldrd. */ + /* TODO: VFP load. */ if ((insn & 0x0d5f0000) == 0x051f0000) { /* ldr reg, [pc, #im] */ offset = insn & 0xfff; if (!(insn & 0x00800000)) - offset = -offset; + offset = -offset; + max_pool = 4096; + type = 0; + } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) { + /* FPA ldf. */ + offset = (insn & 0xff) << 2; + if (!(insn & 0x00800000)) + offset = -offset; + max_pool = 1024; + type = 1; + } else if ((insn & 0x0fff0000) == 0x028f0000) { + /* Some gcc load a doubleword immediate with + add regN, pc, #imm + ldmia regN, {regN, regM} + Hope and pray the compiler never generates somethin like + add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */ + int r; + + r = (insn & 0xf00) >> 7; + offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r)); + max_pool = 1024; + type = 2; + } else { + max_pool = 0; + type = -1; + } + if (type >= 0) { + /* PC-relative load needs fixing up. */ + if (spare > max_pool - offset) + spare = max_pool - offset; if ((offset & 3) !=0) - error("%s:%04x: ldr pc offset must be 32 bit aligned", + error("%s:%04x: pc offset must be 32 bit aligned", + name, start_offset + p - p_start); + if (offset < 0) + error("%s:%04x: Embedded literal value", name, start_offset + p - p_start); pc_offset = p - p_start + offset + 8; - if (pc_offset <= (p - p_start) || + if (pc_offset <= (p - p_start) || pc_offset >= (p_end - p_start)) - error("%s:%04x: ldr pc offset must point inside the function code", + error("%s:%04x: pc offset must point inside the function code", name, start_offset + p - p_start); if (pc_offset < min_offset) min_offset = pc_offset; if (outfile) { - /* ldr position */ - fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", + /* The intruction position */ + fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", p - p_start); - /* ldr data index */ - data_index = ((p_end - p_start) - pc_offset - 4) >> 2; - fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", + /* The position of the constant pool data. */ + data_index = ((p_end - p_start) - pc_offset) >> 2; + fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", data_index); + fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type); fprintf(outfile, " arm_ldr_ptr++;\n"); - if (data_index >= sizeof(data_allocated)) - error("%s: too many data", name); - if (!data_allocated[data_index]) { - ELF_RELOC *rel; - int i, addend, type; - const char *sym_name, *p; - char relname[1024]; - - data_allocated[data_index] = 1; - - /* data value */ - addend = get32((uint32_t *)(p_start + pc_offset)); - relname[0] = '\0'; - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { - if (rel->r_offset == (pc_offset + start_offset)) { - sym_name = get_rel_sym_name(rel); - /* the compiler leave some unnecessary references to the code */ - get_reloc_expr(relname, sizeof(relname), sym_name); - type = ELF32_R_TYPE(rel->r_info); - if (type != R_ARM_ABS32) - error("%s: unsupported data relocation", name); - break; - } - } - fprintf(outfile, " arm_data_ptr[%d] = 0x%x", - data_index, addend); - if (relname[0] != '\0') - fprintf(outfile, " + %s", relname); - fprintf(outfile, ";\n"); - } } } p += 4; } + + /* Copy and relocate the constant pool data. */ data_size = (p_end - p_start) - min_offset; if (data_size > 0 && outfile) { - fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); + spare += min_offset; + fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2); + fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size); + fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n" + " arm_pool_ptr = gen_code_ptr + %d;\n", + spare, spare); + + data_index = 0; + for (pc_offset = min_offset; + pc_offset < p_end - p_start; + pc_offset += 4) { + + ELF_RELOC *rel; + int i, addend, type; + const char *sym_name; + char relname[1024]; + + /* data value */ + addend = get32((uint32_t *)(p_start + pc_offset)); + relname[0] = '\0'; + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { + if (rel->r_offset == (pc_offset + start_offset)) { + sym_name = get_rel_sym_name(rel); + /* the compiler leave some unnecessary references to the code */ + get_reloc_expr(relname, sizeof(relname), sym_name); + type = ELF32_R_TYPE(rel->r_info); + if (type != R_ARM_ABS32) + error("%s: unsupported data relocation", name); + break; + } + } + fprintf(outfile, " arm_data_ptr[%d] = 0x%x", + data_index, addend); + if (relname[0] != '\0') + fprintf(outfile, " + %s", relname); + fprintf(outfile, ";\n"); + + data_index++; + } } - /* the last instruction must be a mov pc, lr */ if (p == p_start) goto arm_ret_error; p -= 4; insn = get32((uint32_t *)p); - if ((insn & 0xffff0000) != 0xe91b0000) { + /* The last instruction must be an ldm instruction. There are several + forms generated by gcc: + ldmib sp, {..., pc} (implies a sp adjustment of +4) + ldmia sp, {..., pc} + ldmea fp, {..., pc} */ + if ((insn & 0xffff8000) == 0xe99d8000) { + if (outfile) { + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n", + p - p_start); + } + p += 4; + } else if ((insn & 0xffff8000) != 0xe89d8000 + && (insn & 0xffff8000) != 0xe91b8000) { arm_ret_error: if (!outfile) printf("%s: invalid epilog\n", name); } - return p - p_start; + return p - p_start; } #endif @@ -1346,7 +1432,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, #define MAX_ARGS 3 /* 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, int gen_switch) { int copy_size = 0; @@ -1392,7 +1478,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } copy_size = len; } -#endif +#endif #elif defined(HOST_PPC) { uint8_t *p; @@ -1409,8 +1495,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, p = (void *)(p_end - 2); if (p == p_start) error("empty code for %s", name); - if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4) - error("br %%r14 expected at the end of %s", name); + if ((get16((uint16_t *)p) & 0xfff0) != 0x07f0) + error("br expected at the end of %s", name); copy_size = p - p_start; } #elif defined(HOST_ALPHA) @@ -1424,7 +1510,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #endif if (get32((uint32_t *)p) != 0x6bfa8001) error("ret expected at the end of %s", name); - copy_size = p - p_start; + copy_size = p - p_start; } #elif defined(HOST_IA64) { @@ -1440,6 +1526,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC) { +#define INSN_SAVE 0x9de3a000 +#define INSN_RET 0x81c7e008 +#define INSN_RETL 0x81c3e008 +#define INSN_RESTORE 0x81e80000 +#define INSN_RETURN 0x81cfe008 +#define INSN_NOP 0x01000000 +#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp +#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp + uint32_t start_insn, end_insn1, end_insn2; uint8_t *p; p = (void *)(p_end - 8); @@ -1448,13 +1543,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -128) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE) + /* SPARC v7: ret; restore; */ ; + else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP) + /* SPARC v9: return; nop; */ ; + else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP) + /* SPARC v7: retl; sub %sp, nn, %sp; */ ; + else + error("ret; restore; not found at end of %s", name); + } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) { + ; } else { error("No save at the beginning of %s", name); } @@ -1462,7 +1565,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) + if (skip_insn == INSN_NOP) p -= 4; } #endif @@ -1470,36 +1573,58 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC64) { +#define INSN_SAVE 0x9de3a000 +#define INSN_RET 0x81c7e008 +#define INSN_RETL 0x81c3e008 +#define INSN_RESTORE 0x81e80000 +#define INSN_RETURN 0x81cfe008 +#define INSN_NOP 0x01000000 +#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp +#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp + uint32_t start_insn, end_insn1, end_insn2, skip_insn; uint8_t *p; p = (void *)(p_end - 8); +#if 0 + /* XXX: check why it occurs */ if (p <= p_start) error("empty code for %s", name); +#endif start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); - if ((start_insn & ~0x1fff) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -256) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE) + /* SPARC v7: ret; restore; */ ; + else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP) + /* SPARC v9: return; nop; */ ; + else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP) + /* SPARC v7: retl; sub %sp, nn, %sp; */ ; + else + error("ret; restore; not found at end of %s", name); + } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) { + ; } else { error("No save at the beginning of %s", name); } - + /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); if (skip_insn == 0x01000000) p -= 4; } - + copy_size = p - p_start; } #elif defined(HOST_ARM) { + uint32_t insn; + if ((p_end - p_start) <= 16) error("%s: function too small", name); if (get32((uint32_t *)p_start) != 0xe1a0c00d || @@ -1508,7 +1633,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, error("%s: invalid prolog", name); p_start += 12; start_offset += 12; - copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, + insn = get32((uint32_t *)p_start); + if ((insn & 0xffffff00) == 0xe24dd000) { + /* Stack adjustment. Assume op uses the frame pointer. */ + p_start -= 4; + start_offset -= 4; + } + copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, relocs, nb_relocs); } #elif defined(HOST_M68K) @@ -1519,12 +1650,32 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, error("empty code for %s", name); // remove NOP's, probably added for alignment while ((get16((uint16_t *)p) == 0x4e71) && - (p>p_start)) + (p>p_start)) p -= 2; if (get16((uint16_t *)p) != 0x4e75) error("rts expected at the end of %s", name); copy_size = p - p_start; } +#elif defined(HOST_MIPS) || defined(HOST_MIPS64) + { +#define INSN_RETURN 0x03e00008 +#define INSN_NOP 0x00000000 + + uint8_t *p = p_end; + + if (p < (p_start + 0x8)) { + error("empty code for %s", name); + } else { + uint32_t end_insn1, end_insn2; + + p -= 0x8; + end_insn1 = get32((uint32_t *)(p + 0x0)); + end_insn2 = get32((uint32_t *)(p + 0x4)); + if (end_insn1 != INSN_RETURN && end_insn2 != INSN_NOP) + error("jr ra not found at end of %s", name); + } + copy_size = p - p_start; + } #else #error unsupported CPU #endif @@ -1549,7 +1700,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } - + nb_args = 0; while (nb_args < MAX_ARGS && args_present[nb_args]) nb_args++; @@ -1586,7 +1737,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, sym_name = get_rel_sym_name(rel); if(!sym_name) continue; - if (*sym_name && + if (*sym_name && !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL) && !strstart(sym_name, "__op_gen_label", NULL)) { @@ -1599,8 +1750,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #endif #if defined(__APPLE__) -/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */ - fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name); + /* Set __attribute((unused)) on darwin because we + want to avoid warning when we don't use the symbol. */ + fprintf(outfile, " extern char %s __attribute__((unused));\n", sym_name); #elif defined(HOST_IA64) if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B) /* @@ -1624,7 +1776,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { EXE_SYM *sym; const char *sym_name, *p; - unsigned long val; + host_ulong val; int n; for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { @@ -1632,7 +1784,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (strstart(sym_name, "__op_label", &p)) { uint8_t *ptr; unsigned long offset; - + /* test if the variable refers to a label inside the code we are generating */ #ifdef CONFIG_FORMAT_COFF @@ -1656,7 +1808,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #ifdef CONFIG_FORMAT_MACH offset -= section_hdr[sym->n_sect-1].addr; #endif - val = *(unsigned long *)(ptr + offset); + val = *(host_ulong *)(ptr + offset); #ifdef ELF_USES_RELOCA { int reloc_shndx, nb_relocs1, j; @@ -1664,7 +1816,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* try to find a matching relocation */ reloc_shndx = find_reloc(sym->st_shndx); if (reloc_shndx) { - nb_relocs1 = shdr[reloc_shndx].sh_size / + 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++) { @@ -1676,7 +1828,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } -#endif +#endif if (val >= start_offset && val <= start_offset + copy_size) { n = strtol(p, NULL, 10); fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset)); @@ -1685,7 +1837,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } - /* load parameres in variables */ + /* load parameters in variables */ for(i = 0; i < nb_args; i++) { fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1); } @@ -1693,7 +1845,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* patch relocations */ #if defined(HOST_I386) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1716,18 +1868,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, continue; } - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); addend = get32((uint32_t *)(text + rel->r_offset)); #ifdef CONFIG_FORMAT_ELF type = ELF32_R_TYPE(rel->r_info); switch(type) { case R_386_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_386_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", - reloc_offset, name, reloc_offset, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1749,12 +1901,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, type = rel->r_type; switch(type) { case DIR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case DISP32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", - reloc_offset, name, reloc_offset, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported i386 relocation (%d)", type); @@ -1767,7 +1919,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_X86_64) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1775,22 +1927,22 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { case R_X86_64_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", + reloc_offset, relname, addend); break; case R_X86_64_32S: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", + reloc_offset, relname, addend); break; case R_X86_64_PC32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", - reloc_offset, name, reloc_offset, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", + reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported X86_64 relocation (%d)", type); @@ -1801,7 +1953,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, #elif defined(HOST_PPC) { #ifdef CONFIG_FORMAT_ELF - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1821,31 +1973,31 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, n, reloc_offset); continue; } - - get_reloc_expr(name, sizeof(name), sym_name); + + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { case R_PPC_ADDR32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_PPC_ADDR16_LO: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", + reloc_offset, relname, addend); break; case R_PPC_ADDR16_HI: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", + reloc_offset, relname, addend); break; case R_PPC_ADDR16_HA: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", + reloc_offset, relname, addend); break; case R_PPC_REL24: /* warning: must be at 32 MB distancy */ - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", - reloc_offset, reloc_offset, name, reloc_offset, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", + reloc_offset, reloc_offset, relname, reloc_offset, addend); break; default: error("unsupported powerpc relocation (%d)", type); @@ -1853,98 +2005,97 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } #elif defined(CONFIG_FORMAT_MACH) - struct scattered_relocation_info *scarel; - struct relocation_info * rel; - char final_sym_name[256]; - const char *sym_name; - const char *p; - int slide, sslide; - int i; - - for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) { - unsigned int offset, length, value = 0; - unsigned int type, pcrel, isym = 0; - unsigned int usesym = 0; - - if(R_SCATTERED & rel->r_address) { - scarel = (struct scattered_relocation_info*)rel; - offset = (unsigned int)scarel->r_address; - length = scarel->r_length; - pcrel = scarel->r_pcrel; - type = scarel->r_type; - value = scarel->r_value; - } else { - value = isym = rel->r_symbolnum; - usesym = (rel->r_extern); - offset = rel->r_address; - length = rel->r_length; - pcrel = rel->r_pcrel; - type = rel->r_type; - } - - slide = offset - start_offset; - - if (!(offset >= start_offset && offset < start_offset + size)) - continue; /* not in our range */ - - sym_name = get_reloc_name(rel, &sslide); - - if(usesym && symtab[isym].n_type & N_STAB) - continue; /* don't handle STAB (debug sym) */ - - if (sym_name && strstart(sym_name, "__op_jmp", &p)) { - int n; - n = strtol(p, NULL, 10); - fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", - n, slide); - continue; /* Nothing more to do */ - } - - if(!sym_name) - { - fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n", - name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type); - continue; /* dunno how to handle without final_sym_name */ - } - - get_reloc_expr(final_sym_name, sizeof(final_sym_name), - sym_name); - switch(type) { - case PPC_RELOC_BR24: - if (!strstart(sym_name,"__op_gen_label",&p)) { - fprintf(outfile, "{\n"); - fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide); - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", - slide, slide, name, sslide ); - fprintf(outfile, "}\n"); - } else { - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n", - slide, slide, final_sym_name, slide); - } - break; - case PPC_RELOC_HI16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", - slide, final_sym_name, sslide); - break; - case PPC_RELOC_LO16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n", - slide, final_sym_name, sslide); + struct scattered_relocation_info *scarel; + struct relocation_info * rel; + char final_sym_name[256]; + const char *sym_name; + const char *p; + int slide, sslide; + int i; + + for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + unsigned int offset, length, value = 0; + unsigned int type, pcrel, isym = 0; + unsigned int usesym = 0; + + if(R_SCATTERED & rel->r_address) { + scarel = (struct scattered_relocation_info*)rel; + offset = (unsigned int)scarel->r_address; + length = scarel->r_length; + pcrel = scarel->r_pcrel; + type = scarel->r_type; + value = scarel->r_value; + } else { + value = isym = rel->r_symbolnum; + usesym = (rel->r_extern); + offset = rel->r_address; + length = rel->r_length; + pcrel = rel->r_pcrel; + type = rel->r_type; + } + + slide = offset - start_offset; + + if (!(offset >= start_offset && offset < start_offset + size)) + continue; /* not in our range */ + + sym_name = get_reloc_name(rel, &sslide); + + if(usesym && symtab[isym].n_type & N_STAB) + continue; /* don't handle STAB (debug sym) */ + + if (sym_name && strstart(sym_name, "__op_jmp", &p)) { + int n; + n = strtol(p, NULL, 10); + fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", + n, slide); + continue; /* Nothing more to do */ + } + + if(!sym_name) { + fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n", + name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type); + continue; /* dunno how to handle without final_sym_name */ + } + + get_reloc_expr(final_sym_name, sizeof(final_sym_name), + sym_name); + switch(type) { + case PPC_RELOC_BR24: + if (!strstart(sym_name,"__op_gen_label",&p)) { + fprintf(outfile, "{\n"); + fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", + slide, slide, name, sslide); + fprintf(outfile, "}\n"); + } else { + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n", + slide, slide, final_sym_name, slide); + } break; - case PPC_RELOC_HA16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", - slide, final_sym_name, sslide); - break; - default: - error("unsupported powerpc relocation (%d)", type); - } - } + case PPC_RELOC_HI16: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", + slide, final_sym_name, sslide); + break; + case PPC_RELOC_LO16: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n", + slide, final_sym_name, sslide); + break; + case PPC_RELOC_HA16: + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", + slide, final_sym_name, sslide); + break; + default: + error("unsupported powerpc relocation (%d)", type); + } + } #else #error unsupport object format #endif } #elif defined(HOST_S390) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -1952,22 +2103,35 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { case R_390_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_390_16: - fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_390_8: - fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); + break; + case R_390_PC32DBL: + if (ELF32_ST_TYPE(symtab[ELFW(R_SYM)(rel->r_info)].st_info) == STT_SECTION) { + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) += " + "((long)&%s - (long)gen_code_ptr) >> 1;\n", + reloc_offset, name); + } + else + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "(%s + %d - ((uint32_t)gen_code_ptr + %d)) >> 1;\n", + reloc_offset, relname, addend, reloc_offset); break; default: error("unsupported s390 relocation (%d)", type); @@ -2035,7 +2199,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, { unsigned long sym_idx; long code_offset; - char name[256]; + char relname[256]; int type; long addend; @@ -2058,7 +2222,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, n, code_offset); continue; } - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF64_R_TYPE(rel->r_info); addend = rel->r_addend; switch(type) { @@ -2066,19 +2230,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, fprintf(outfile, " ia64_imm64(gen_code_ptr + %ld, " "%s + %ld);\n", - code_offset, name, addend); + code_offset, relname, addend); break; case R_IA64_LTOFF22X: case R_IA64_LTOFF22: fprintf(outfile, " IA64_LTOFF(gen_code_ptr + %ld," " %s + %ld, %d);\n", - code_offset, name, addend, + code_offset, relname, addend, (type == R_IA64_LTOFF22X)); break; case R_IA64_LDXMOV: fprintf(outfile, " ia64_ldxmov(gen_code_ptr + %ld," - " %s + %ld);\n", code_offset, name, addend); + " %s + %ld);\n", code_offset, relname, addend); break; case R_IA64_PCREL21B: @@ -2087,7 +2251,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " ia64_imm21b(gen_code_ptr + %ld," " (long) (%s + %ld -\n\t\t" "((long) gen_code_ptr + %ld)) >> 4);\n", - code_offset, name, addend, + code_offset, relname, addend, code_offset & ~0xfUL); } else { fprintf(outfile, @@ -2108,7 +2272,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2116,14 +2280,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { case R_SPARC_32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2131,7 +2295,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2139,7 +2303,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2148,9 +2312,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - reloc_offset, reloc_offset, name, addend, + reloc_offset, reloc_offset, relname, addend, reloc_offset); break; + case R_SPARC_WDISP22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3fffff) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " + " & 0x3fffff);\n", + rel->r_offset - start_offset, + rel->r_offset - start_offset, + relname, addend, + rel->r_offset - start_offset); + break; default: error("unsupported sparc relocation (%d)", type); } @@ -2159,7 +2335,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_SPARC64) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2167,14 +2343,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); - type = ELF64_R_TYPE(rel->r_info); + get_reloc_expr(relname, sizeof(relname), sym_name); + type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { case R_SPARC_32: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + reloc_offset, relname, addend); break; case R_SPARC_HI22: fprintf(outfile, @@ -2182,7 +2358,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3fffff) " " | (((%s + %d) >> 10) & 0x3fffff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_LO10: fprintf(outfile, @@ -2190,7 +2366,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, "((*(uint32_t *)(gen_code_ptr + %d)) " " & ~0x3ff) " " | ((%s + %d) & 0x3ff);\n", - reloc_offset, reloc_offset, name, addend); + reloc_offset, reloc_offset, relname, addend); + break; + case R_SPARC_OLO10: + addend += ELF64_R_TYPE_DATA (rel->r_info); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3ff) " + " | ((%s + %d) & 0x3ff);\n", + reloc_offset, reloc_offset, relname, addend); break; case R_SPARC_WDISP30: fprintf(outfile, @@ -2199,23 +2384,90 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, " & ~0x3fffffff) " " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " " & 0x3fffffff);\n", - reloc_offset, reloc_offset, name, addend, + reloc_offset, reloc_offset, relname, addend, reloc_offset); break; + case R_SPARC_WDISP22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x3fffff) " + " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) " + " & 0x3fffff);\n", + reloc_offset, reloc_offset, relname, addend, + reloc_offset); + break; + case R_SPARC_HH22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | (((%s + %d) >> 42) & 0x00000000);\n", + reloc_offset, reloc_offset, relname, addend); + break; + + case R_SPARC_LM22: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | (((%s + %d) >> 10) & 0x00000000);\n", + reloc_offset, reloc_offset, relname, addend); + break; + + case R_SPARC_HM10: + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + %d) = " + "((*(uint32_t *)(gen_code_ptr + %d)) " + " & ~0x00000000) " + " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n", + reloc_offset, reloc_offset, relname, addend); + break; + default: - error("unsupported sparc64 relocation (%d)", type); + error("unsupported sparc64 relocation (%d) for symbol %s", type, relname); } } } } #elif defined(HOST_ARM) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; - - arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, + uint32_t insn; + + insn = get32((uint32_t *)(p_start + 4)); + /* If prologue ends in sub sp, sp, #const then assume + op has a stack frame and needs the frame pointer. */ + if ((insn & 0xffffff00) == 0xe24dd000) { + int i; + uint32_t opcode; + opcode = 0xe28db000; /* add fp, sp, #0. */ +#if 0 +/* ??? Need to undo the extra stack adjustment at the end of the op. + For now just leave the stack misaligned and hope it doesn't break anything + too important. */ + if ((insn & 4) != 0) { + /* Preserve doubleword stack alignment. */ + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n", + insn + 4); + opcode -= 4; + } +#endif + insn = get32((uint32_t *)(p_start - 4)); + /* Calculate the size of the saved registers, + excluding pc. */ + for (i = 0; i < 15; i++) { + if (insn & (1 << i)) + opcode += 4; + } + fprintf(outfile, + " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode); + } + arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end, relocs, nb_relocs); for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { @@ -2225,18 +2477,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, /* the compiler leave some unnecessary references to the code */ if (sym_name[0] == '\0') continue; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = get32((uint32_t *)(text + rel->r_offset)); reloc_offset = rel->r_offset - start_offset; switch(type) { case R_ARM_ABS32: - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", - reloc_offset, name, addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", + reloc_offset, relname, addend); break; case R_ARM_PC24: - fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", - reloc_offset, addend, name); + case R_ARM_JUMP24: + case R_ARM_CALL: + fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", + reloc_offset, addend, relname); break; default: error("unsupported arm relocation (%d)", type); @@ -2246,7 +2500,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } #elif defined(HOST_M68K) { - char name[256]; + char relname[256]; int type; int addend; int reloc_offset; @@ -2256,20 +2510,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, rel->r_offset < start_offset + copy_size) { sym = &(symtab[ELFW(R_SYM)(rel->r_info)]); sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; - get_reloc_expr(name, sizeof(name), sym_name); + get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { case R_68K_32: fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ; - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", - reloc_offset, name, addend ); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", + reloc_offset, relname, addend ); break; case R_68K_PC32: fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset); - fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", - reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend); + fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", + reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend); break; default: error("unsupported m68k relocation (%d)", type); @@ -2277,6 +2531,81 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, } } } +#elif defined(HOST_MIPS) || defined(HOST_MIPS64) + { + for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) { + if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) { + char relname[256]; + int type; + int addend; + int reloc_offset; + + sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name; + /* the compiler leave some unnecessary references to the code */ + if (sym_name[0] == '\0') + continue; + get_reloc_expr(relname, sizeof(relname), sym_name); + type = ELF32_R_TYPE(rel->r_info); + addend = get32((uint32_t *)(text + rel->r_offset)); + reloc_offset = rel->r_offset - start_offset; + switch (type) { + case R_MIPS_26: + fprintf(outfile, " /* R_MIPS_26 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "(0x%x & ~0x3fffff) " + "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " + " & 0x3fffff);\n", + reloc_offset, addend, addend, relname, reloc_offset); + break; + case R_MIPS_HI16: + fprintf(outfile, " /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (((%s - 0x8000) >> 16) & 0xffff);\n", + reloc_offset, reloc_offset, relname); + break; + case R_MIPS_LO16: + fprintf(outfile, " /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (%s & 0xffff);\n", + reloc_offset, reloc_offset, relname); + break; + case R_MIPS_PC16: + fprintf(outfile, " /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "(0x%x & ~0xffff) " + "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) " + " & 0xffff);\n", + reloc_offset, addend, addend, relname, reloc_offset); + break; + case R_MIPS_GOT16: + case R_MIPS_CALL16: + fprintf(outfile, " /* R_MIPS_GOT16 RELOC, offset 0x%x, name %s */\n", + rel->r_offset, sym_name); + fprintf(outfile, + " *(uint32_t *)(gen_code_ptr + 0x%x) = " + "((*(uint32_t *)(gen_code_ptr + 0x%x)) " + " & ~0xffff) " + " | (((%s - 0x8000) >> 16) & 0xffff);\n", + reloc_offset, reloc_offset, relname); + break; + default: + error("unsupported MIPS relocation (%d)", type); + } + } + } + } #else #error unsupported CPU #endif @@ -2336,9 +2665,31 @@ int gen_file(FILE *outfile, int out_type) gen_code(name, sym->st_value, sym->st_size, outfile, 0); } } - + } else { /* generate big code generation switch */ + +#ifdef HOST_ARM + /* We need to know the size of all the ops so we can figure out when + to emit constant pools. This must be consistent with opc.h. */ +fprintf(outfile, +"static const uint32_t arm_opc_size[] = {\n" +" 0,\n" /* end */ +" 0,\n" /* nop */ +" 0,\n" /* nop1 */ +" 0,\n" /* nop2 */ +" 0,\n"); /* nop3 */ + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { + const char *name; + name = get_sym_name(sym); + if (strstart(name, OP_PREFIX, NULL)) { + fprintf(outfile, " %d,\n", sym->st_size); + } + } +fprintf(outfile, +"};\n"); +#endif + fprintf(outfile, "int dyngen_code(uint8_t *gen_code_buf,\n" " uint16_t *label_offsets, uint16_t *jmp_offsets,\n" @@ -2349,10 +2700,36 @@ fprintf(outfile, " const uint32_t *opparam_ptr;\n"); #ifdef HOST_ARM +/* Arm is tricky because it uses constant pools for loading immediate values. + We assume (and require) each function is code followed by a constant pool. + All the ops are small so this should be ok. For each op we figure + out how much "spare" range we have in the load instructions. This allows + us to insert subsequent ops in between the op and the constant pool, + eliminating the neeed to jump around the pool. + + We currently generate: + + [ For this example we assume merging would move op1_pool out of range. + In practice we should be able to combine many ops before the offset + limits are reached. ] + op1_code; + op2_code; + goto op3; + op2_pool; + op1_pool; +op3: + op3_code; + ret; + op3_pool; + + Ideally we'd put op1_pool before op2_pool, but that requires two passes. + */ fprintf(outfile, " uint8_t *last_gen_code_ptr = gen_code_buf;\n" " LDREntry *arm_ldr_ptr = arm_ldr_table;\n" -" uint32_t *arm_data_ptr = arm_data_table;\n"); +" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" +/* Initialise the parmissible pool offset to an arbitary large value. */ +" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n"); #endif #ifdef HOST_IA64 { @@ -2418,19 +2795,33 @@ fprintf(outfile, " opc_ptr = opc_buf;\n" " opparam_ptr = opparam_buf;\n"); - /* Generate prologue, if needed. */ + /* Generate prologue, if needed. */ fprintf(outfile, -" for(;;) {\n" -" switch(*opc_ptr++) {\n" -); +" for(;;) {\n"); + +#ifdef HOST_ARM +/* Generate constant pool if needed */ +fprintf(outfile, +" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n" +" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n" +" last_gen_code_ptr = gen_code_ptr;\n" +" arm_ldr_ptr = arm_ldr_table;\n" +" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" +" arm_pool_ptr = gen_code_ptr + 0x1000000;\n" +" }\n"); +#endif + +fprintf(outfile, +" switch(*opc_ptr++) {\n"); for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { const char *name; name = get_sym_name(sym); if (strstart(name, OP_PREFIX, NULL)) { #if 0 - printf("%4d: %s pos=0x%08x len=%d\n", + printf("%4d: %s pos=0x%08x len=%d\n", i, name, sym->st_value, sym->st_size); #endif #if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF) @@ -2457,17 +2848,6 @@ fprintf(outfile, " goto the_end;\n" " }\n"); -#ifdef HOST_ARM -/* generate constant table if needed */ -fprintf(outfile, -" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n" -" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n" -" last_gen_code_ptr = gen_code_ptr;\n" -" arm_ldr_ptr = arm_ldr_table;\n" -" arm_data_ptr = arm_data_table;\n" -" }\n"); -#endif - fprintf(outfile, " }\n" @@ -2483,9 +2863,12 @@ fprintf(outfile, "plt_target, plt_offset);\n }\n"); #endif -/* generate some code patching */ +/* generate some code patching */ #ifdef HOST_ARM -fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); +fprintf(outfile, +"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n" +" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n"); #endif /* flush instruction cache */ fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");