📄 dld_section.c
字号:
#endif u8 *dst; section_for_each(scn, list) {#ifdef DEBUG_RELOCATE if (scn->nreloc) { prmsg("%s: reloc entries\n", scn->name); prmsg("%3s %8s %-20s %8s %8s %-16s %8s %8s\n", "ent", "addr", "symbol", "sym:olg", "sym:new", "type", "original", "new"); }#endif for (i = 0; i < scn->nreloc; i++) { /* * XXX: ___pinit__ blames. * we disable the value check at the moment. */#if 0 int safe_relocation = 1;#else int safe_relocation = 0;#endif rel = &scn->reloc[i]; if (rel->type & COFF_R_EXTRA_BIT) { if ((i = extra_relocate(scn, i)) < 0) return -1; continue; } if (!strcmp(rel->sym.sym->name, "cinit")) { /* * If the module has been compiled with * RAM model initialization, it should * not refer to the "cinit" symbol, but * otherwise there can be this reference. * the kernel side, cinit is dummy and * the value is illegal (maybe ffffffff). * * We allow the case the module has not * been compiled with RAM model. */ safe_relocation = 0; } vaddr_relative = rel->vaddr - scn->vaddr_orig;#ifdef DEBUG_RELOCATE delta = rel_sym_delta(scn, rel, &sym_org, &sym_new);#else delta = rel_sym_delta(scn, rel);#endif dst = &scn->data[vaddr_relative]; switch (rel->type) { case COFF_R_ABS: /* no relocation */ break; case COFF_R_LD3_k4: /* unsigned 4-bit shift immed. */ val = (dst[0] >> 4) + delta; if (safe_relocation && (val > 0xf)) goto val_invalid; dst[0] = (val << 4) & (dst[0] & 0xf); break; case COFF_R_RELBYTE: /* 8-bit */ case COFF_R_LD3_K8: /* 8-bit signed direct */ val = dst[0] + delta; if (safe_relocation && (val > 0x7f) && (val < 0xffffff80)) goto val_invalid; dst[0] = val; break; case COFF_R_LD3_k8: /* 8-bit unsigned direct */ val = dst[0] + delta; if (safe_relocation && (val > 0xff)) goto val_invalid; dst[0] = val; break; case COFF_R_RELWORD: /* 16-bit */ case COFF_R_LD3_K16: /* 16-bit signed direct */ val = COFF_SHORT_H(dst) + delta; if (safe_relocation && (val > 0x7fff) && (val < 0xffff8000)) goto val_invalid; COFF_PUT_SHORT_H(val, dst); break; case COFF_R_LD3_REL16: /* speculation */ case COFF_R_LD3_k16: /* 16-bit unsigned direct */ val = COFF_SHORT_H(dst) + delta; if (safe_relocation && (val > 0xffff)) goto val_invalid; COFF_PUT_SHORT_H(val, dst); break; case COFF_R_REL24: /* 24-bit */ case COFF_R_LD3_REL23: /* 23-bit unsigned value in 24-bit field */ val = COFF_24BIT_H(dst) + delta; if (safe_relocation && (val > 0xffffff)) goto val_invalid; COFF_PUT_24BIT_H(val, dst); break; case COFF_R_RELLONG: val = COFF_LONG_H(dst) + delta; COFF_PUT_LONG_H(val, dst); break; /* * FIXME: * Not sure how those types shold be handled */ case COFF_R_LD3_DMA: /* 7 MSBs in a byte (unsigned) */ case COFF_R_LD3_MDP: /* 7 bits spanning 2bytes (unsigned) */ case COFF_R_LD3_PDP: /* 9 bits spanning 2bytes (unsigned) */ case COFF_R_LD3_l8: /* 8-bit unsigned relative */ case COFF_R_LD3_l16: /* 16-bit unsigned relative */ case COFF_R_LD3_L8: /* 8-bit signed relative */ case COFF_R_LD3_L16: /* 16-bit signed relative */ case COFF_R_LD3_k5: /* unsigned 5-bit shift immed. */ case COFF_R_LD3_K5: /* signed 5-bit shift immed. */ case COFF_R_LD3_k6: /* unsigned 6-bit shift immed. */ case COFF_R_LD3_k12: /* unsigned 12-bit shift immed. */ default: prmsg("We can't handle this type of " "relocation [%04x]! " "(section %s, entry %d)\n" "Please contact to developer.\n", rel->type, scn->name, i); return -1; }#ifdef DEBUG_RELOCATE prmsg(" %2d %08lx %-20s %08lx %08lx" " %04x(%-10s) %08lx %08lx\n", i, vaddr_relative, rel->sym.sym->name, sym_org, sym_new, rel->type, reloc_name(rel->type), val - delta, val);#endif } } return 0;val_invalid:#ifdef DEBUG_RELOCATE prmsg(" %2d %08lx %-20s %08lx %08lx" " %04x(%-10s) %08lx %08lx\n", i, vaddr_relative, rel->sym.sym->name, sym_org, sym_new, rel->type, reloc_name(rel->type), val - delta, val);#endif prmsg("relocated value %x is invalid for relocation type %s!\n", val, reloc_name(rel->type)); return -1;}static int extra_relocate(struct section *scn, int i){ u32 vaddr = scn->reloc[i].vaddr; u32 vaddr_relative = vaddr - scn->vaddr_orig;#define STKSZ 10 u32 stack[STKSZ]; int sp = 0; for (; i < scn->nreloc; i++) { struct reloc *rel = &scn->reloc[i]; if (rel->vaddr != vaddr) break; switch (rel->type) { case COFF_R_EX_PSHSYM: stack[sp++] = rel_sym_val(scn, rel); break; case COFF_R_EX_PSHVAL: stack[sp++] = rel->sym.val; break; case COFF_R_EX_PSHINTOFF: /* * internal reloc + offset value */ stack[sp++] = scn->vaddr + rel->sym.val; break; case COFF_R_EX_ADD: stack[0] += stack[--sp]; break; case COFF_R_EX_SUB: stack[0] -= stack[--sp]; break; case COFF_R_EX_RSHIFT: stack[0] >>= stack[--sp]; break; case COFF_R_EX_MASK: stack[0] &= stack[--sp]; break; /* * XXX: * Couldn't find out the difference among * three below. */ case COFF_R_EX_WRITE1: case COFF_R_EX_WRITE2: case COFF_R_EX_WRITE3: { u8 roff, loff, masksz; u32 msb_ptr; u32 parm, mask, offset; u8 *dst; parm = rel->sym.val; roff = (parm >> 16) & 0xff; masksz = (parm >> 8) & 0xff; loff = parm & 0xff; if ((masksz > 32) || (roff > 32) || (loff > 32) || (roff & 0x07)) { prmsg("illegal writeback parm [%08x]! " "(section %s, entry %d)\n" "Please contact to developer.\n", parm, scn->name, i); return -1; } mask = 0xffffffff >> (32-masksz) << loff; msb_ptr = vaddr_relative + (roff-loff+7)/8 - 4; dst = &scn->data[msb_ptr]; offset = COFF_LONG_H(dst); stack[0] = (offset & ~mask) | ((stack[0] << loff) & mask); COFF_PUT_LONG_H(stack[0],dst); break; } default: prmsg("We can't handle this type of relocation [%04x]! " "(section %s, entry %d)\n" "Please contact to developer.\n", rel->type, scn->name, i); }#ifdef DEBUG_RELOCATE switch (rel->type) { case COFF_R_EX_PSHSYM: prmsg(" %2d %08lx %-20s %8s %08lx" " %04x(%-10s)\n", i, vaddr_relative, rel->sym.sym->name, "", stack[sp-1], rel->type, reloc_name(rel->type)); break; case COFF_R_EX_PSHVAL: case COFF_R_EX_PSHINTOFF: prmsg(" %2d %08lx %08lx%10s %8s %8s" " %04x(%-10s)\n", i, vaddr_relative, rel->sym.val, "", "", "", rel->type, reloc_name(rel->type)); break; case COFF_R_EX_ADD: case COFF_R_EX_SUB: case COFF_R_EX_RSHIFT: case COFF_R_EX_MASK: prmsg(" %2d %08lx %-20s %8s %8s" " %04x(%-10s) %8s (%08lx)\n", i, vaddr_relative, "", "", "", rel->type, reloc_name(rel->type), "", stack[0]); break; case COFF_R_EX_WRITE1: case COFF_R_EX_WRITE2: case COFF_R_EX_WRITE3: prmsg(" %2d %08lx %08lx%10s %8s %8s" " %04x(%-10s) %8s (%08lx)\n", i, vaddr_relative, rel->sym.val, "", "", "", rel->type, reloc_name(rel->type), "", stack[0]); break; }#endif } return i-1;}inline int rel_sym_field_type(u16 type){ switch (type) { case COFF_R_RELBYTE: case COFF_R_RELWORD: case COFF_R_LD3_REL16: case COFF_R_REL24: case COFF_R_LD3_REL23: case COFF_R_RELLONG: case COFF_R_LD3_DMA: case COFF_R_LD3_MDP: case COFF_R_LD3_PDP: case COFF_R_LD3_k8: case COFF_R_LD3_k16: case COFF_R_LD3_K8: case COFF_R_LD3_K16: case COFF_R_LD3_l8: case COFF_R_LD3_l16: case COFF_R_LD3_L8: case COFF_R_LD3_L16: case COFF_R_LD3_k4: case COFF_R_LD3_k5: case COFF_R_LD3_K5: case COFF_R_LD3_k6: case COFF_R_LD3_k12: case COFF_R_EX_PSHSYM: return RELOC_SYMBOL_FIELD_TYPE_SYMBOL; case COFF_R_EX_PSHVAL: case COFF_R_EX_PSHINTOFF: case COFF_R_EX_WRITE1: case COFF_R_EX_WRITE2: case COFF_R_EX_WRITE3: return RELOC_SYMBOL_FIELD_TYPE_VALUE; default: return RELOC_SYMBOL_FIELD_TYPE_INVALID; }}static char *reloc_name(u16 type){ switch (type) { case COFF_R_ABS: return("ABS"); case COFF_R_REL24: return("REL24"); case COFF_R_RELBYTE: return("RELBYTE"); case COFF_R_RELWORD: return("RELWORD"); case COFF_R_RELLONG: return("RELLONG"); case COFF_R_LD3_DMA: return("LD3_DMA"); case COFF_R_LD3_MDP: return("LD3_MDP"); case COFF_R_LD3_PDP: return("LD3_PDP"); case COFF_R_LD3_REL23: return("LD3_REL23"); case COFF_R_LD3_k8: return("LD3_k8"); case COFF_R_LD3_k16: return("LD3_k16"); case COFF_R_LD3_K8: return("LD3_K8"); case COFF_R_LD3_K16: return("LD3_K16"); case COFF_R_LD3_l8: return("LD3_l8"); case COFF_R_LD3_l16: return("LD3_l16"); case COFF_R_LD3_L8: return("LD3_L8"); case COFF_R_LD3_L16: return("LD3_L16"); case COFF_R_LD3_k4: return("LD3_k4"); case COFF_R_LD3_k5: return("LD3_k5"); case COFF_R_LD3_K5: return("LD3_K5"); case COFF_R_LD3_k6: return("LD3_k6"); case COFF_R_LD3_k12: return("LD3_k12"); case COFF_R_LD3_REL16: return("LD3_REL16"); case COFF_R_EX_ADD: return("EX_ADD"); case COFF_R_EX_SUB: return("EX_SUB"); case COFF_R_EX_RSHIFT: return("EX_RSHIFT"); case COFF_R_EX_MASK: return("EX_MASK"); case COFF_R_EX_WRITE1: return("EX_WRITE1"); case COFF_R_EX_WRITE2: return("EX_WRITE2"); case COFF_R_EX_PSHSYM: return("EX_PSHSYM"); case COFF_R_EX_PSHVAL: return("EX_PSHVAL"); case COFF_R_EX_PSHINTOFF: return("EX_PSHINTOFF"); case COFF_R_EX_WRITE3: return("EX_WRITE3"); } return("unknown");}#ifdef DEBUG_RELOCATEstatic u32 __rel_sym_val(struct section *scn, struct reloc *rel, u32 *org, u32 *new, int delta)#elsestatic u32 __rel_sym_val(struct section *scn, struct reloc *rel, int delta)#endif{ struct symbol *sym; struct section *scn_target; u32 _org, _new, val; sym = rel->sym.sym; if (sym == &symbol_internalreloc) { _org = scn->vaddr_orig; _new = scn->vaddr; scn_target = scn; } else { _org = sym->value_orig; _new = sym->value; scn_target = sym->scn; } /* * text pointer: byte address * data pointer: word address */ if (!(scn_target->flags & COFF_STYP_TEXT)) { _org >>= 1; _new >>= 1; } val = delta ? _new - _org : _new;#ifdef DEBUG_RELOCATE /* debug info return */ if (org) *org = _org; if (new) *new = _new;#endif return val;}static int section_loadtype(struct section *scn){ if (scn->size == 0) return LDTYP_ZEROSZ; if (scn->data == NULL) { if (scn->flags & COFF_STYP_BSS) return LDTYP_LOAD; else return LDTYP_NODATA; } if (scn->flags & (COFF_STYP_DSECT | COFF_STYP_NOLOAD | COFF_STYP_PAD)) return LDTYP_NOLOAD; if (scn->flags & COFF_STYP_COPY) { if (!strcmp(scn->name, ".cinit")) return LDTYP_CINIT_RAM; else return LDTYP_NOLOAD; } return LDTYP_LOAD;}static struct section *section_find_by_addr(struct list_head *list, u32 addr){ struct section *scn; section_for_each(scn, list) { if ((addr >= scn->vaddr) && (addr < scn->vaddr + scn->size) && !(scn->flags & (COFF_STYP_DSECT | COFF_STYP_NOLOAD | COFF_STYP_PAD | COFF_STYP_COPY))) return scn; } /* not found */ return NULL;}struct section *section_find_by_name(struct list_head *list, char *name){ struct section *scn; section_for_each(scn, list) { if (!strcmp(scn->name, name)) return scn; } /* not found */ return NULL;}void section_sendstat(struct list_head *list, int fd){ char buf[256]; size_t strsz = 256 - SERVER_EVENT_HDRSZ; struct server_event *e = (struct server_event *)buf; struct section *scn; int cnt;#ifdef STICKY_LIST if (list == NULL) list = &g_scnlist;#endif e->event = DLD_EVENT_STRING; cnt = snprintf(e->data.s, strsz, "%-20s %8s %8s %4s %10s\n", "name", "vaddr", "size", "nrel", "flags"); e->len = SERVER_EVENT_HDRSZ + cnt; write(fd, e, e->len); section_for_each(scn, list) { int real_addr; real_addr = (scn->flags & (COFF_STYP_DSECT | COFF_STYP_NOLOAD | COFF_STYP_PAD | COFF_STYP_COPY)) ? 0 : 1; cnt = snprintf(e->data.s, strsz, "%-20s 0x%06lx%c 0x%06lx%c %4ld 0x%08lx\n", scn->name, scn->vaddr, real_addr ? ' ' : '-', scn->size, scn->data ? ' ' : '-', scn->nreloc, scn->flags); e->len = SERVER_EVENT_HDRSZ + cnt; write(fd, e, e->len); }}/* * debug stuff */void section_printstat(struct list_head *list){ struct section *scn; prmsg("section list status ...\n"); prmsg(" %-20s %8s %8s %4s %10s\n", "name", "vaddr", "size", "nrel", "flags"); section_for_each(scn, list) { int real_addr; real_addr = (scn->flags & (COFF_STYP_DSECT | COFF_STYP_NOLOAD | COFF_STYP_PAD | COFF_STYP_COPY)) ? 0 : 1; prmsg(" %-20s 0x%06lx%c 0x%06lx%c %4ld 0x%08lx\n", scn->name, scn->vaddr, real_addr ? ' ' : '-', scn->size, scn->data ? ' ' : '-', scn->nreloc, scn->flags); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -