/**************************************************************** * * * Copyright 2001, 2013 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include #include "gtm_string.h" #include "gtm_unistd.h" #include "gtm_stdio.h" #include #include "compiler.h" #include "urx.h" #include "objlabel.h" #include "gtmio.h" #include "zroutines.h" #include "incr_link.h" #include "cachectl.h" #include "obj_file.h" #include "stringpool.h" #include "gtm_limits.h" #include "min_max.h" #include "gtmdbglvl.h" #include "cmd_qlf.h" /* needed for CQ_UTF8 */ #include "gtm_text_alloc.h" #define RELOCATE(field, type, base) field = (type)((unsigned char *)(field) + (UINTPTR_T)(base)) #define RELREAD 50 /* number of relocation entries to buffer */ /* This macro will check if the file is an old non-shared-binary variant of GT.M code and if * so just return false to signal a recompile. The assumption is that if we fall out of this * macro that there is truly a problem and other measures should be taken (e.g. call zlerror()). * At some point this code can be disabled with the NO_NONUSB_RECOMPILE varible defined. Rather * than keep old versions of control blocks around that will confuse the issue, we know that the * routine header of these versions started 10 32bit words into the object. Read in the eight * bytes from that location and check against the JSB_MARKER we still use today. */ #ifndef NO_NONUSB_RECOMPILE # define CHECK_NONUSB_RECOMPILE \ { \ if (-1 != (status = (ssize_t)lseek(file_desc, COFFHDRLEN, SEEK_SET))) \ { \ DOREADRC_OBJFILE(file_desc, marker, SIZEOF(JSB_MARKER) - 1, status); \ } else \ status = errno; \ if ((0 == status) && (0 == MEMCMP_LIT(marker, JSB_MARKER))) \ { \ free(hdr); \ return FALSE; /* Signal recompile */ \ } \ } #else # define CHECK_NONUSB_RECOMPILE /* No old recompile check is being generated */ #endif /* INCR_LINK - read and process a mumps object module. Link said module to currently executing image */ LITREF char gtm_release_name[]; LITREF int4 gtm_release_name_len; static unsigned char *sect_ro_rel, *sect_rw_rel, *sect_rw_nonrel; static boolean_t shlib; static rhdtyp *hdr; GBLREF mident_fixed zlink_mname; GBLREF mach_inst jsb_action[JSB_ACTION_N_INS]; GBLREF uint4 gtmDebugLevel; GBLREF boolean_t gtm_utf8_mode; ZOS_ONLY( GBLDEF unsigned char *text_section; GBLDEF boolean_t extended_symbols_present; GBLDEF int total_length; GBLDEF int text_counter = 0; ) typedef struct res_list_struct { struct res_list_struct *next, *list; unsigned int addr, symnum; } res_list; error_def(ERR_DLLCHSETM); error_def(ERR_DLLCHSETUTF8); error_def(ERR_DLLVERSION); error_def(ERR_INVOBJ); error_def(ERR_LOADRUNNING); error_def(ERR_TEXT); void res_free(res_list *root); boolean_t addr_fix(int file, unsigned char *shdr, urx_rtnref *urx_lcl); void zl_error(int4 file, zro_ent *zroe, int4 err, int4 len, char *addr, int4 len2, char *addr2); void zl_error_hskpng(int4 file); int cacheflush (void *addr, long nbytes, int cache_select); bool incr_link (int file_desc, zro_ent *zro_entry) { rhdtyp *old_rhead; int sect_ro_rel_size, sect_rw_rel_size; ssize_t status, sect_rw_nonrel_size; lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top; mident_fixed module_name; pre_v5_mident *pre_v5_routine_name; urx_rtnref urx_lcl_anchor; int order; boolean_t dynlits; size_t offset_correction; unsigned char *shdr, *rel_base; mval *curlit, *littop; lab_tabent *curlbe, *lbetop; var_tabent *curvar, *vartop; char name_buf[PATH_MAX+1]; int name_buf_len, alloc_len; char marker[SIZEOF(JSB_MARKER) - 1]; char *rw_rel_start; AIX_ONLY( FILHDR hddr; unsigned short magic; ) ZOS_ONLY( ESD symbol; total_length = 0; extended_symbols_present = FALSE; text_counter = 0; memset(&symbol, 0 , SIZEOF(ESD)); assert(NULL == text_section); ZOS_FREE_TEXT_SECTION; ) urx_lcl_anchor.len = 0; urx_lcl_anchor.addr = 0; urx_lcl_anchor.lab = 0; urx_lcl_anchor.next = 0; shlib = FALSE; hdr = NULL; shdr = NULL; sect_ro_rel = sect_rw_rel = sect_rw_nonrel = NULL; if (file_desc) { /* This is a disk resident object we will be reading in */ shlib = FALSE; assert(NULL == zro_entry); } else { shlib = TRUE; assert(zro_entry); } /* Get the routine header where we can make use of it */ hdr = (rhdtyp *)malloc(SIZEOF(rhdtyp)); if (shlib) { /* Make writable copy of header as header of record. * On some platforms, the address returned by dlsym() is not the actual shared code address, but normally * an address to the linkage table, eg. TOC (AIX), PLT (HP-UX). Computing the actual shared code address * is platform dependent and is handled by the macro (see incr_link_sp.h) */ shdr = (unsigned char *)GET_RTNHDR_ADDR(zro_entry->shrsym); memcpy(hdr, shdr, SIZEOF(rhdtyp)); hdr->shlib_handle = zro_entry->shrlib; } else { /* Seek past native object headers to get GT.M object's routine header */ /* To check if it is not an xcoff64 bit .o */ AIX_ONLY( DOREADRC(file_desc, &hddr, SIZEOF(FILHDR), status); if (0 == status) { magic = hddr.f_magic; if (-1 == (status = (ssize_t)lseek(file_desc, -(SIZEOF(FILHDR)), SEEK_SET))) status = errno; if (magic != U64_TOCMAGIC) return FALSE; } else zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); ) /* In the GOFF .o on zOS, if the symbol name(name of the module) exceeds ESD_NAME_MAX_LENGTH (8), * * then 2 extra extended records are emitted, which causes the start of text section to vary */ #ifdef __MVS__ DOREADRC(file_desc, &symbol, SIZEOF(symbol), status); /* This is HDR record */ if (0 == status) { DOREADRC(file_desc, &symbol, SIZEOF(symbol), status) /* First symbol (ESD record) */ if (0 == status) { if (0x01 == symbol.ptv[1]) /* which means the extended records are there */ extended_symbols_present = TRUE; else { assert(0x0 == symbol.ptv[1]); extended_symbols_present = FALSE; } } } if (0 != status) zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); #endif if (-1 != (status = (ssize_t)lseek(file_desc, NATIVE_HDR_LEN, SEEK_SET))) { ZOS_ONLY(extract_text(file_desc, &total_length);) DOREADRC_OBJFILE(file_desc, hdr, SIZEOF(rhdtyp), status); } else status = errno; if (0 != status) { CHECK_NONUSB_RECOMPILE; zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } } if ((0 != memcmp(hdr->jsb, (char *)jsb_action, SIZEOF(jsb_action))) || (0 != memcmp(&hdr->jsb[SIZEOF(jsb_action)], JSB_MARKER, MIN(STR_LIT_LEN(JSB_MARKER), SIZEOF(hdr->jsb) - SIZEOF(jsb_action))))) { if (!shlib) /* Shared library cannot recompile so this is always an error */ { CHECK_NONUSB_RECOMPILE; } zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } /* Binary version check. If no match, shlib gets error, otherwise signal recompile */ if (MAGIC_COOKIE != hdr->objlabel) { if (shlib) { if (MAGIC_COOKIE_V5 > hdr->objlabel) { /* The library was built using a version prior to V50FT01. The routine_name field of the * pre-V5 routine header was an 8-byte char array, so read the routine name in the old format */ int len; pre_v5_routine_name = (pre_v5_mident *)((char*)hdr + PRE_V5_RTNHDR_RTNOFF); for (len = 0; len < SIZEOF(pre_v5_mident) && pre_v5_routine_name->c[len]; len++) ; zl_error(0, zro_entry, ERR_DLLVERSION, len, &(pre_v5_routine_name->c[0]), zro_entry->str.len, zro_entry->str.addr); } #if defined(__osf__) || defined(__hppa) else if (MAGIC_COOKIE_V52 > hdr->objlabel) { /* Note: routine_name field has not been relocated yet, so compute its absolute * address in the shared library and use it */ v50v51_mstr *mstr5051; /* declare here so don't have to conditionally add above */ mstr5051 = (v50v51_mstr *)((char *)hdr + V50V51_RTNHDR_RTNMSTR_OFFSET); zl_error(0, zro_entry, ERR_DLLVERSION, mstr5051->len, ((char *)shdr + *(int4 *)((char *)hdr + V50V51_FTNHDR_LITBASE_OFFSET) + (int4)mstr5051->addr), zro_entry->str.len, zro_entry->str.addr); } #endif else /* V52 or later but not current version */ { /* Note: routine_name field has not been relocated yet, so compute its absolute * address in the shared library and use it */ zl_error(0, zro_entry, ERR_DLLVERSION, hdr->routine_name.len, (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr, zro_entry->str.len, zro_entry->str.addr); } } ZOS_FREE_TEXT_SECTION; return FALSE; } if (((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) || (!(hdr->compiler_qlf & CQ_UTF8) && gtm_utf8_mode)) { /* object file compiled with a different $ZCHSET is being used */ if (shlib) /* Shared library cannot recompile so this is always an error */ { /* Note: routine_name field has not been relocated yet, so compute its absolute address * in the shared library and use it */ if ((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) { zl_error(0, zro_entry, ERR_DLLCHSETUTF8, (int)hdr->routine_name.len, (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr, (int)zro_entry->str.len, zro_entry->str.addr); } else { zl_error(0, zro_entry, ERR_DLLCHSETM, (int)hdr->routine_name.len, (char *)shdr + (UINTPTR_T)hdr->literal_text_adr + (UINTPTR_T)hdr->routine_name.addr, (int)zro_entry->str.len, zro_entry->str.addr); } } zl_error_hskpng(file_desc); if ((hdr->compiler_qlf & CQ_UTF8) && !gtm_utf8_mode) rts_error(VARLSTCNT(6) ERR_INVOBJ, 0, ERR_TEXT, 2, LEN_AND_LIT("Object compiled with CHSET=UTF-8 which is different from $ZCHSET")); else rts_error(VARLSTCNT(6) ERR_INVOBJ, 0, ERR_TEXT, 2, LEN_AND_LIT("Object compiled with CHSET=M which is different from $ZCHSET")); } /* Read in and/or relocate the pointers to the various sections. To understand the size calculations * being done note that the contents of the various xxx_adr pointers in the routine header are * initially the offsets from the start of the object. This is so we can address the various sections * via offset now while linking and via address later during runtime. * * Read-only releasable section */ dynlits = DYNAMIC_LITERALS_ENABLED(hdr); rw_rel_start = RW_REL_START_ADR(hdr); /* Marks end of R/O-release section and start of R/W-release section */ if (shlib) rel_base = shdr; else { sect_ro_rel_size = (unsigned int)((INTPTR_T)rw_rel_start - (INTPTR_T)hdr->ptext_adr); sect_ro_rel = GTM_TEXT_ALLOC(sect_ro_rel_size); /* It should be aligned well at this point but make a debug level check to verify */ assert((INTPTR_T)sect_ro_rel == ((INTPTR_T)sect_ro_rel & ~(LINKAGE_PSECT_BOUNDARY - 1))); DOREADRC_OBJFILE(file_desc, sect_ro_rel, sect_ro_rel_size, status); if (0 != status) zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); /* The offset correction is the amount that needs to be applied to a given storage area that * is no longer contiguous with the routine header. In this case, the code and other sections * are no longer contiguous with the routine header but the initial offsets in the routine * header make the assumption that they are. Therefore these sections have a base address equal * to the length of the routine header. The offset correction is what will adjust the base * address so that this offset is removed and the pointer can now truly point to the section * it needs to point to. * * An example may make this more clear. We have two blocks of storage: block A and block B. Now * block A has 2 fields that will ultimately point into various places in block B. These pointers * are initialized to be the offset from the start of block A to the position in block B. Now we * have two cases. In the first case block A and block B are contiguous. Therefore in order to * relocate the addresses in block A, all you have to do is add the base address of block A to * those addresses and they then properly address the areas in block B. Case 2 is that block A * and block B are not contiguous. In this case, to properly adjust the addresses in block A, we * need to do two things. Obviously we need the address for block B. But the offsets currently in * the addresses in block A assume that block A is the origin, not block B so the length of block A * must be subtracted from the offsets to provide the true offset into block B. Then we can add the * address of the block B to this address and have now have the addesses in block A properly address * the areas in block B. In this case, block A is the routine header, block B is the read-only * releasable section. Case one is when the input is from a shared library, case 2 when from a file. */ offset_correction = (size_t)hdr->ptext_adr; rel_base = sect_ro_rel - offset_correction; } RELOCATE(hdr->ptext_adr, unsigned char *, rel_base); RELOCATE(hdr->ptext_end_adr, unsigned char *, rel_base); RELOCATE(hdr->lnrtab_adr, lnr_tabent *, rel_base); RELOCATE(hdr->literal_text_adr, unsigned char *, rel_base); if (dynlits) RELOCATE(hdr->literal_adr, mval *, rel_base); /* Read-write releasable section */ sect_rw_rel_size = (int)((INTPTR_T)hdr->labtab_adr - (INTPTR_T)rw_rel_start); sect_rw_rel = malloc(sect_rw_rel_size); if (shlib) memcpy(sect_rw_rel, shdr + (INTPTR_T)rw_rel_start, sect_rw_rel_size); else { DOREADRC_OBJFILE(file_desc, sect_rw_rel, sect_rw_rel_size, status); if (0 != status) zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } offset_correction = (size_t)rw_rel_start; rel_base = sect_rw_rel - offset_correction; if (!dynlits) RELOCATE(hdr->literal_adr, mval *, rel_base); RELOCATE(hdr->vartab_adr, var_tabent *, rel_base); /* Also read-write releasable is the linkage section which had no initial value and was thus * not resident in the object. The values in this section will be setup later by addr_fix() * and/or auto-zlink. Note we always allocate at least one element here just so we don't get * the potentially unaligned "null string" address provided by gtm_malloc() when a zero * length is requested. */ alloc_len = hdr->linkage_len * SIZEOF(lnk_tabent); hdr->linkage_adr = (lnk_tabent *)malloc((0 != alloc_len) ? alloc_len : SIZEOF(lnk_tabent)); assert(PADLEN(hdr->linkage_adr, SIZEOF(lnk_tabent) == 0)); assert(((UINTPTR_T)hdr->linkage_adr % SIZEOF(lnk_tabent)) == 0); memset((char *)hdr->linkage_adr, 0, (hdr->linkage_len * SIZEOF(lnk_tabent))); /* Relocations for read-write releasable section. Perform relocation on literal mval table and * variable table entries since they both point to the offsets from the beginning of the * literal text pool. The relocations for the linkage section is done in addr_fix() */ if (!dynlits) { for (curlit = hdr->literal_adr, littop = curlit + hdr->literal_len; curlit < littop; ++curlit) if (curlit->str.len) RELOCATE(curlit->str.addr, char *, hdr->literal_text_adr); } for (curvar = hdr->vartab_adr, vartop = curvar + hdr->vartab_len; curvar < vartop; ++curvar) { assert(0 < curvar->var_name.len); RELOCATE(curvar->var_name.addr, char *, hdr->literal_text_adr); } /* Fixup header's source path and routine names as they both point to the offsets from the * beginning of the literal text pool */ hdr->src_full_name.addr += (INTPTR_T)hdr->literal_text_adr; hdr->routine_name.addr += (INTPTR_T)hdr->literal_text_adr; if (GDL_PrintEntryPoints & gtmDebugLevel) { /* Prepare name and address for announcement.. */ name_buf_len = (PATH_MAX > hdr->src_full_name.len) ? hdr->src_full_name.len : PATH_MAX; memcpy(name_buf, hdr->src_full_name.addr, name_buf_len); name_buf[name_buf_len] = '\0'; PRINTF("incr_link: %s loaded at 0x%08lx\n", name_buf, (long unsigned int) hdr->ptext_adr); } /* Read-write non-releasable section */ sect_rw_nonrel_size = hdr->labtab_len * SIZEOF(lab_tabent); sect_rw_nonrel = malloc(sect_rw_nonrel_size); if (shlib) memcpy(sect_rw_nonrel, shdr + (INTPTR_T)hdr->labtab_adr, sect_rw_nonrel_size); else { DOREADRC_OBJFILE(file_desc, sect_rw_nonrel, sect_rw_nonrel_size, status); if (0 != status) zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } hdr->labtab_adr = (lab_tabent *)sect_rw_nonrel; /* Relocations for read-write non-releasable section. Perform relocation on label table entries. */ for (curlbe = hdr->labtab_adr, lbetop = curlbe + hdr->labtab_len; curlbe < lbetop; ++curlbe) { RELOCATE(curlbe->lab_name.addr, char *, hdr->literal_text_adr); RELOCATE(curlbe->lnr_adr, lnr_tabent *, hdr->lnrtab_adr); } /* Remaining initialization */ hdr->current_rhead_adr = hdr; assert(hdr->routine_name.len < SIZEOF(zlink_mname.c)); memcpy(&zlink_mname.c[0], hdr->routine_name.addr, hdr->routine_name.len); zlink_mname.c[hdr->routine_name.len] = 0; /* Do address fix up with relocation and symbol entries from the object. Note that shdr will * never be dereferenced except under a test of the shlib static flag to indicate we are processing * a shared library. */ if (!addr_fix(file_desc, shdr, &urx_lcl_anchor)) { urx_free(&urx_lcl_anchor); zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0); } /* Register new routine in routine name vector displacing old one and performing any necessary cleanup */ if (!zlput_rname(hdr)) { urx_free(&urx_lcl_anchor); /* Copy routine name to local variable because zl_error frees it. */ memcpy(&module_name.c[0], hdr->routine_name.addr, hdr->routine_name.len); zl_error(file_desc, zro_entry, ERR_LOADRUNNING, (int)hdr->routine_name.len, &module_name.c[0], 0, 0); } /* Fix up of routine headers for old versions of routine so they point to the newest version */ old_rhead = hdr->old_rhead_adr; lbt_bot = hdr->labtab_adr; lbt_top = lbt_bot + hdr->labtab_len; while (old_rhead) { lbt_ent = lbt_bot; olbt_bot = old_rhead->labtab_adr; olbt_top = olbt_bot + old_rhead->labtab_len; for (olbt_ent = olbt_bot; olbt_ent < olbt_top; olbt_ent++) { /* Match new label entries with old label entries */ for (; lbt_ent < lbt_top; lbt_ent++) { MIDENT_CMP(&olbt_ent->lab_name, &lbt_ent->lab_name, order); if (order <= 0) break; } if ((lbt_ent < lbt_top) && !order) { /* Have a label name match. Update line pointer for this entry */ olbt_ent->lnr_adr = lbt_ent->lnr_adr; olbt_ent->has_parms = lbt_ent->has_parms; } else { /* This old label entry has no match. Mark as undefined */ olbt_ent->lnr_adr = NULL; olbt_ent->has_parms = 0; } } old_rhead->src_full_name = hdr->src_full_name; old_rhead->routine_name = hdr->routine_name; old_rhead->vartab_len = hdr->vartab_len; old_rhead->vartab_adr = hdr->vartab_adr; old_rhead->ptext_adr = hdr->ptext_adr; old_rhead->ptext_end_adr = hdr->ptext_end_adr; old_rhead->lnrtab_adr = hdr->lnrtab_adr; old_rhead->lnrtab_len = hdr->lnrtab_len; old_rhead->current_rhead_adr = hdr; old_rhead->temp_mvals = hdr->temp_mvals; old_rhead->temp_size = hdr->temp_size; old_rhead->linkage_adr = hdr->linkage_adr; old_rhead->literal_adr = hdr->literal_adr; old_rhead->literal_text_adr = hdr->literal_text_adr; old_rhead->literal_len = hdr->literal_len; old_rhead = (rhdtyp *)old_rhead->old_rhead_adr; } /* Add local unresolves to global chain freeing elements that already existed in the global chain */ urx_add(&urx_lcl_anchor); /* Resolve all unresolved entries in the global chain that reference this routine */ urx_resolve(hdr, (lab_tabent *)lbt_bot, (lab_tabent *)lbt_top); if (!shlib) cacheflush(hdr->ptext_adr, (hdr->ptext_end_adr - hdr->ptext_adr), BCACHE); ZOS_FREE_TEXT_SECTION; return TRUE; } boolean_t addr_fix (int file, unsigned char *shdr, urx_rtnref *urx_lcl) { res_list *res_root, *new_res, *res_temp, *res_temp1; unsigned char *symbols, *sym_temp, *sym_temp1, *symtop, *res_addr; struct relocation_info rel[RELREAD], *rel_ptr; int numrel, rel_read, string_size, sym_size, i; ssize_t status; mident_fixed rtnid, labid; mstr rtn_str; rhdtyp *rtn; lab_tabent *label, *labtop; boolean_t labsym; urx_rtnref *urx_rp; urx_addr *urx_tmpaddr; res_root = NULL; numrel = (int)((hdr->sym_table_off - hdr->rel_table_off) / SIZEOF(struct relocation_info)); if ((numrel * SIZEOF(struct relocation_info)) != (hdr->sym_table_off - hdr->rel_table_off)) return FALSE; /* Size was not even multiple of relocation entries */ while (numrel > 0) { if (shlib) { /* All relocation entries already available */ rel_read = numrel; rel_ptr = (struct relocation_info *)((char *)shdr + hdr->rel_table_off); } else { /* Buffer the relocation entries */ rel_read = (numrel < RELREAD ? numrel : RELREAD); DOREADRC_OBJFILE(file, &rel[0], rel_read * SIZEOF(struct relocation_info), status); if (0 != status) { res_free(res_root); return FALSE; } rel_ptr = &rel[0]; } numrel -= rel_read; for (; rel_read; --rel_read, ++rel_ptr) { new_res = (res_list *)malloc(SIZEOF(*new_res)); new_res->symnum = rel_ptr->r_symbolnum; new_res->addr = rel_ptr->r_address; new_res->next = new_res->list = 0; /* Insert the relocation entry in symbol number order on the unresolved chain */ if (!res_root) res_root = new_res; else { res_temp1 = NULL; for (res_temp = res_root; res_temp && res_temp->symnum < new_res->symnum; res_temp = res_temp->next) res_temp1 = res_temp; if (!res_temp) res_temp1->next = new_res; else { /* More than one reference to this symbol. Chain multiple refs in list */ if (res_temp->symnum == new_res->symnum) { new_res->list = res_temp->list; res_temp->list = new_res; } else { if (res_temp1) { new_res->next = res_temp1->next; res_temp1->next = new_res; } else { assert(res_temp == res_root); new_res->next = res_root; res_root = new_res; } } } } } } if (!res_root) return TRUE; /* No unresolved symbols .. we have been successful */ /* Read in the symbol table text area. First word is length of following section */ if (shlib) { memcpy(&string_size, shdr + hdr->sym_table_off, SIZEOF(string_size)); symbols = shdr + hdr->sym_table_off + SIZEOF(string_size); string_size -= SIZEOF(string_size); } else { DOREADRC_OBJFILE(file, &string_size, SIZEOF(string_size), status); if (0 != status) { res_free(res_root); return FALSE; } string_size -= SIZEOF(string_size); symbols = malloc(string_size); DOREADRC_OBJFILE(file, symbols, string_size, status); if (0 != status) { free(symbols); res_free(res_root); return FALSE; } } /* Match up unresolved entries with the null terminated symbol name entries from the * symbol text pool we just read in. */ sym_temp = sym_temp1 = symbols; symtop = symbols + string_size; for (i = 0; res_root; i++) { for (; i < res_root->symnum; i++) { /* Forward space symbols until our symnum index (i) matches the symbol * we are processing in res_root. */ for (; *sym_temp; sym_temp++) { /* Find end of *this* symbol we are bypassing */ if (sym_temp >= symtop) { if (!shlib) free(symbols); res_free(res_root); return FALSE; } } sym_temp++; sym_temp1 = sym_temp; } assert(i == res_root->symnum); /* Find end of routine name that we care about */ for (; *sym_temp1 != '.' && *sym_temp1; sym_temp1++) { if (sym_temp1 >= symtop) { if (!shlib) free(symbols); res_free(res_root); return FALSE; } } sym_size = (int)(sym_temp1 - sym_temp); assert(sym_size <= MAX_MIDENT_LEN); memcpy(&rtnid.c[0], sym_temp, sym_size); rtnid.c[sym_size] = 0; if ('_' == rtnid.c[0]) rtnid.c[0] = '%'; assert((mid_len(&zlink_mname) != sym_size) || (0 != memcmp(&zlink_mname.c[0], &rtnid.c[0], sym_size))); rtn_str.addr = &rtnid.c[0]; rtn_str.len = sym_size; rtn = find_rtn_hdr(&rtn_str); /* Routine already resolved? */ sym_size = 0; labsym = FALSE; /* If symbol is for a label, find the end of the label name */ if ('.' == *sym_temp1) { sym_temp1++; sym_temp = sym_temp1; for (; *sym_temp1; sym_temp1++) { if (sym_temp1 >= symtop) { if (!shlib) free(symbols); res_free(res_root); return FALSE; } } sym_size = (int)(sym_temp1 - sym_temp); assert(sym_size <= MAX_MIDENT_LEN); memcpy(&labid.c[0], sym_temp, sym_size); labid.c[sym_size] = 0; if ('_' == labid.c[0]) labid.c[0] = '%'; labsym = TRUE; } sym_temp1++; sym_temp = sym_temp1; if (rtn) { /* The routine part at least is known */ if (!labsym) res_addr = (unsigned char *)rtn; /* resolve to routine header */ else { /* Look our target label up in the routines label table */ label = rtn->labtab_adr; labtop = label + rtn->labtab_len; for (; label < labtop && ((sym_size != label->lab_name.len) || memcmp(&labid.c[0], label->lab_name.addr, sym_size)); label++) ; if (label < labtop) res_addr = (unsigned char *)&label->lnr_adr; /* resolve to label entry address */ else res_addr = NULL; /* Label not found .. potential future problem. For now * just leave it unresolved */ } if (res_addr) { /* We can fully resolve this symbol now */ res_temp = res_root->next; while(res_root) { /* Resolve all entries for this known symbol */ ((lnk_tabent * )((char *)hdr->linkage_adr + res_root->addr))->ext_ref = (char_ptr_t)res_addr; res_temp1 = res_root->list; free(res_root); res_root = res_temp1; } res_root = res_temp; continue; } } /* This symbol is unknown. Put on the (local) unresolved extern chain -- either for labels or routines */ urx_rp = urx_putrtn(rtn_str.addr, (int)rtn_str.len, urx_lcl); /* Find/create unresolved node for routine */ res_temp = res_root->next; while(res_root) { /* add unresolved addr entry to existing or new routine and/or label node. */ if (labsym) urx_putlab(&labid.c[0], sym_size, urx_rp, (char *)hdr->linkage_adr + res_root->addr); else { urx_tmpaddr = (urx_addr *)malloc(SIZEOF(urx_addr)); urx_tmpaddr->next = urx_rp->addr; urx_tmpaddr->addr = (INTPTR_T *)((char *)hdr->linkage_adr + res_root->addr); urx_rp->addr = urx_tmpaddr; } res_temp1 = res_root->list; free(res_root); res_root = res_temp1; } res_root = res_temp; } if (!shlib) free(symbols); return TRUE; } /* Release the resolution chain .. Called as part of an error since normal processing will * have already released all elements on this chain. */ void res_free (res_list *root) { res_list *temp; while (root) { while (root->list) { temp = root->list->list; free(root->list); root->list = temp; } temp = root->next; free(root); root = temp; } } /* ZL_ERROR - perform cleanup and signal errors found in zlinking a mumps object module */ void zl_error (int4 file, zro_ent *zroe, int4 err, int4 len, char *addr, int4 len2, char *addr2) { ZOS_FREE_TEXT_SECTION; zl_error_hskpng(file); /* 0, 2, or 4 arguments */ if (0 == len) rts_error(VARLSTCNT(1) err); else if (0 == len2) rts_error(VARLSTCNT(4) err, 2, len, addr); else rts_error(VARLSTCNT(6) err, 4, len, addr, len2, addr2); } /* ZL_ERROR-housekeeping */ void zl_error_hskpng(int4 file) { int rc; if (!shlib) { /* Only non shared library links have these areas to free */ if (hdr) free(hdr); if (sect_ro_rel) GTM_TEXT_FREE(sect_ro_rel); if (sect_rw_rel) free(sect_rw_rel); if (sect_rw_nonrel) free(sect_rw_nonrel); CLOSEFILE_RESET(file, rc); /* resets "file" to FD_INVALID */ } }