📄 loadecofflib.c
字号:
goto error; } } } /* flush instruction cache before execution */ if (optHdr.tsize != NULL) cacheTextUpdate (pText, optHdr.tsize); } if (externalsBuf != NULL) { free ((char *) externalsBuf); /* finished with externalsBuf */ externalsBuf = NULL; } /* * free memory that was used (free should be as early as possible to * allow memory reuse, which is very important for large object modules) */ for (ix = 0; ix < MAX_SCNS; ix++) if (relsPtr[ix] != NULL) { free((char *) relsPtr[ix]); relsPtr[ix] = NULL; } /* return load addresses, where called for */ if (ppText != NULL) *ppText = pText; if (ppData != NULL) *ppData = pData; if (ppBss != NULL) *ppBss = pBss; /* clear out bss */ bzero (pBss, (int) seg.sizeBss); /* * Add the segments to the module. * This has to happen after the relocation gets done. * If the relocation happens first, the checksums won't be * correct. */ moduleSegAdd (moduleId, SEGMENT_TEXT, pText, seg.sizeText, seg.flagsText); moduleSegAdd (moduleId, SEGMENT_DATA, pData, seg.sizeData, seg.flagsData); moduleSegAdd (moduleId, SEGMENT_BSS, pBss, seg.sizeBss, seg.flagsBss); if (status == OK) return (moduleId); else return (NULL); /* error: * clean up dynamically allocated temporary buffers and return ERROR */error: for (ix = 0; ix < MAX_SCNS; ix++) { if (sectPtr[ix] != NULL) free((char *) sectPtr[ix]); if (relsPtr[ix] != NULL) free((char *) relsPtr[ix]); } if (stringsBuf != NULL) free (stringsBuf); if (externalsBuf != NULL) free ((char *) externalsBuf); if (externalSyms != NULL) free ((char *) externalSyms); moduleDelete (moduleId); return (NULL); }/********************************************************************************* rdEcoffSymTab -** This is passed a pointer to an ecoff symbol table and processes* each of the external symbols defined therein. This processing performs* two functions:* 1) defined symbols are entered in the system symbol table as* specified by the "symFlag" argument:* ALL_SYMBOLS = all defined symbols (LOCAL and GLOBAL) are added,* GLOBAL_SYMBOLS = only external (GLOBAL) symbols are added,* NO_SYMBOLS = no symbols are added;* 2) any undefined externals are looked up in the system table, and* if found, entered in the specified 'externals' array. This array* is indexed by the symbol number (position in the symbol table).* Note that only undefined externals are filled in in 'externals' and* that values for all other types of symbols are unchanged (i.e. left* as garbage!). This is ok because 'externals' is only used to * perform relocations relative to previously undefined externals.* Note that "common" symbols have type undefined external - the value* field of the symbol will be non-zero for type common, indicating* the size of the object.** If more than the specified maximum number of symbols are found in the* symbol table, the externals array is extended to accomodate the additional* symbols.* If an undefined external cannot be found in the system symbol table,* an error message is printed, but ERROR is not returned until the entire* symbol table has been read, which allows all undefined externals to be* looked up.* Stabs and absolute symbols are automatically discarded.** RETURNS: OK or ERROR** INTERNAL* Local symbols are currently ignored.*/LOCAL STATUS rdEcoffSymTab ( EXTR * pExtSyms, /* pointer to mips external symbols */ FAST int nEnts, /* # of entries in symbol table */ char ***externals, /* pointer to pointer to array to fill in values of undef externals */ int max_symbols, /* max symbols that can be put in 'externals' */ int symFlag, /* symbols to be added to table * ([NO|GLOBAL|ALL]_SYMBOLS) */ SEG_INFO *pSeg, /* pointer to segment information */ char *symStrings, /* symbol string table (only meaningful in BSD 4.2) */ SYMTAB_ID symTbl, /* symbol table to use */ char *pNextCommon, /* next common address in bss */ int group /* symbol group */ ) { FAST char *name; /* symbol name (plus EOS) */ EXTR symbol; /* symbol value */ SYM_TYPE vxSymType; /* ecoff symbol translation */ int sym_num = 0; /* symbol index */ int status = OK; /* return status */ char *adrs; /* table resident symbol address */ SYM_TYPE type; /* ecoff symbol type */ char *bias; /* section relatilve address */ ULONG bssAlignment; /* alignment value of common type */ /* pass 1: process defined symbols */ for (sym_num = 0; sym_num < nEnts; sym_num ++) { /* read in next entry - symbol definition and name string */ symbol = pExtSyms [sym_num]; /* add requested symbols to symbol table */ if ((!COFF_ABS(&symbol)) && /* throw away absolute symbols */ (!COFF_UNDF(&symbol)) && (!COFF_COMM(&symbol)) && (symFlag & LOAD_GLOBAL_SYMBOLS) && COFF_EXT(&symbol)) { /* * symbol name string is in symStrings array indexed * by symbol.iss */ name = symStrings + symbol.asym.iss; /* * I'm not sure the symbol type can tell us what section the * symbol is in so we look at the address. This should be * investigated at a later date. */ if (symbol.U_SYM_VALUE < (long) pSeg->sizeText) bias = (char *) pSeg->addrText; else if (symbol.U_SYM_VALUE < ((long) pSeg->sizeText + (long) pSeg->sizeData)) bias = (char *) ( (long) pSeg->addrData - (long) pSeg->sizeText); else bias = (char *) ((long) pSeg->addrBss - pSeg->sizeText - pSeg->sizeData); if (ecoffToVxSym (&symbol, &vxSymType) == ERROR) printErr (cantConvSymbolType, name, errnoGet()); if (symSAdd (symTbl, name, symbol.U_SYM_VALUE + bias, vxSymType, group) != OK) printErr (cantAddSymErrMsg, name, errnoGet()); /* * add symbol address to externals table, but first * check for enough room in 'externals' table */ if (sym_num == max_symbols) { /* * no more room in symbol table - * make externals table half again as big */ max_symbols += max_symbols / 2; *externals = (char **) realloc ((char *) *externals, max_symbols * sizeof (char *)); if (*externals == NULL) return (ERROR); } /* enter address in table used by relSegment */ (*externals) [sym_num] = symbol.U_SYM_VALUE + bias; } } /* pass 2: process undefined symbols (including commons) */ for (sym_num = 0; sym_num < nEnts; sym_num ++) { /* read in next entry - symbol definition and name string */ symbol = pExtSyms [sym_num]; if ((!(COFF_ABS(&symbol))) && /* throw away absolute symbols */ ((COFF_UNDF(&symbol)) || (COFF_COMM(&symbol)))) { /* * symbol name string is in symStrings array indexed * by symbol.iss */ name = symStrings + symbol.asym.iss; /* * undefined external symbol or "common" symbol - * common symbol type is denoted by undefined external with * the value set to non-zero. * * if symbol is a common, then allocate space and add to * symbol table as BSS */ /* common symbol - create new symbol */ if (COFF_COMM(&symbol) && (symbol.U_SYM_VALUE != 0)) /* do we really need this ? */ { /* * common symbol - create new symbol * * Common symbols are now tacked to the end of the bss * section. This portion of code reads the symbol value * which contains the symbol size and places it appropriately * in the bss section. The function sizeEcoffCommons is used * with the address of the last common added to determine * proper alignment. */ adrs = pNextCommon; bssAlignment = sizeEcoffCommons (&symbol, (ULONG) adrs); bssAlignment -= (ULONG) symbol.U_SYM_VALUE; adrs += bssAlignment; pNextCommon += (symbol.U_SYM_VALUE + bssAlignment); if (symSAdd (symTbl, name, adrs, (N_BSS | N_EXT), group) != OK) printErr (cantAddSymErrMsg, name, errnoGet()); } /* look up undefined external symbol in symbol table */ else if (symFindByNameAndType (symTbl, name, &adrs, &type, N_EXT, N_EXT) != OK) { /* symbol not found in symbol table */ printErr ("undefined symbol: %s\n", name); adrs = NULL; status = ERROR; } /* * add symbol address to externals table, but first * check for enough room in 'externals' table */ if (sym_num == max_symbols) { /* * no more room in symbol table - * make externals table half again as big */ max_symbols += max_symbols / 2; *externals = (char **) realloc ((char *) *externals, max_symbols * sizeof (char *)); if (*externals == NULL) return (ERROR); } (*externals) [sym_num] = adrs; /* enter address in table */ } } return (status); }/********************************************************************************* relSegmentR3k - perform relocation commands for a MIPS segment** This routine reads the specified relocation command segment and performs* all the relocations specified therein.* External relocations are looked up in the 'externals' table.* All other relocations are relative to how much a particular segment has moved.** That was the short explanation. The following is more specific:* Each relocation command is identified as being external or local; * external symbols require the use of the 'externals' table to perform* the relocation while local symbols are relocated relative to a segment* (text or data).** There are the following types of external relocation entries:* -R_REFWORD for externally defined pointers,* -R_HALFWORD ?? would be a 16 bit external pointer but thus far* has not been seen from the MIPS C compiler,* -R_JMPADDR for calls to externalC functions,* -R_REFHI/R_REFLO pairs for accessing and external data* value, and* -unsupported GP (global pointer) relative relocation types which * cause an error to be returned.* * There are local versions of these relocation entries also:* -R_REFWORD for static pointers and arrays,* -R_HALFWORD should be similar to R_REFWORD but have not been * able to get the C compiler to generate it,* -R_JMPADDR for relative jumps to functions (references to functions* located within the load module.* -R_REFHI/R_REFLO combinations for accesses to objects defined in * this file and with local visibility (i.e. static data * structure references).* -unsupported GP (global pointer) relative relocation types which * cause an error to be returned.*** RETURNS: OK or ERROR*/LOCAL STATUS relSegmentR3k ( RELOC *pRelCmds, /* list of mips relocation commands */ SCNHDR *pScnHdr, /* section header for relocation */ char **pExternals, /* addresses of external symbols */ int section, /* section number TEXT, RDATA, BSS ... */ SEG_INFO *pSeg /* section addresses and sizes */ ) { FAST long *pAddress; /* relocation address */ FAST long *pNextAddress; /* next relocation address */ long refhalfSum; /* refhalf sum */ long targetAddr; /* relocation target address */ long relocOffset; /* relocation offset */ long relocConstant; /* general reloc constant */ long relSegment; /* RTEXT, RDATA, ... */ long segment; /* segment we are relocating */ unsigned short nCmds; /* # reloc commands for seg */ RELOC relocCmd; /* relocation structure */ RELOC nextRelocCmd; /* next relocation structure */ long refhiConstant = 0; /* last REFHI constant */ nCmds = pScnHdr->s_nreloc; while ( nCmds > 0 ) { /* read relocation command */ relocCmd = *pRelCmds++; nCmds -= 1; /* * Calculate actual address in memory that needs relocation * and perform external or segment relative relocation */ if ((section == R_SN_TEXT) || (section == R_SN_INIT)) { pAddress = (long *) ((long) pSeg->addrText + relocCmd.r_vaddr); segment = RTEXT; } else { pAddress = (long *) ((long) pSeg->addrData + (relocCmd.r_vaddr - pSeg->sizeText)); segment = RDATA; } /* note: should check for valid pAddress here XXXX */ if (relocCmd.r_extern) /* globlal relocation */ { switch (relocCmd.r_type) { case R_REFWORD: /* * This relocation is performed by adding the 32 bit address * of the symbol to the contents of pAddress. * See IDT Assembly language programmers guide pg. 10-16 */ *pAddress = (*pAddress + (long) pExternals[relocCmd.r_symndx]); break; case R_REFHALF: /* WARNING: UNTESTED */ /* * This case is not well documented by MIPS, and has never * been generated. REFWORD and REFHALF relocation entries * are generally used for pointers, and a case where you have * a 16 bit pointer is very unlikely to occur on a 32 bit * architecture. */ refhalfSum = ((LS16BITS & *pAddress) + (long) pExternals[relocCmd.r_symndx]); if (refhalfSum >= OVERFLOW) refhalfSum &= LS16BITS; *pAddress = (MS16BITS & *pAddress) | (LS16BITS & refhalfSum); break; case R_JMPADDR: /* * For this relocation type the loader determines the address * for the jump, shifts the address right two bits, and adds * the lower 26 bits of the result to the low 26 bits of the * instruction at pAddress (after sign extension). The * results go back into the low 26 bits at pAddress. * The initial check is to see if the jump is within range. * The current address is incremented by 4 because the jump * actually takes place in the branch delay slot of the * current address. * See IDT Assembly language programmers guide pg. 10-16 */ if ((MS4BITS & ((long) pAddress + sizeof(INSTR))) != (MS4BITS & (long) pExternals[relocCmd.r_symndx])) { errnoSet (S_loadEcoffLib_JMPADDR_ERROR); return (ERROR); } targetAddr = (LS26BITS & *pAddress) + (LS26BITS & ((unsigned) pExternals[relocCmd.r_symndx] >> 2)); *pAddress = (MS6BITS & *pAddress) | (LS26BITS & targetAddr); break; case R_REFHI: /* * A refhi relocation is done by reading the next relocation * entry (always the coresponding reflo entry). This least * significant 16 bits are taken from the refhi instruction * and shifted left to form a 32 bit value. This value is * added to the least significant 16 bits of the reflo * instruction (taking into account sign extention) to form * a 32 bit reference pointer. The target address is added * to this constant and placed back in the least significant * 16 bits of each instruction address. The contents of the * lower 16 bits of pAddress (refhiConstant) are saved for any * other reflo entries that the refhi entry may correspond to. * See IDT Assembly language programmers guide pg. 10-16 */ refhiConstant = (*pAddress << 16); nextRelocCmd = *pRelCmds++; nCmds -= 1; if (nextRelocCmd.r_type != R_REFLO) { errnoSet (S_loadEcoffLib_NO_REFLO_PAIR); return (ERROR); } if (segment == RTEXT) { pNextAddress = (long *) ((long) pSeg->addrText + nextRelocCmd.r_vaddr); } else /* segment == RDATA */ { pNextAddress = (long *) ((long) pSeg->addrData + (nextRelocCmd.r_vaddr - (long) pSeg->sizeText)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -