/************************************************************************* Copyright (c) 1984 by Nick de Smith This software is supplied for interest and non-profit making purposes only. Under no circumstance shall it be lent, copied or otherwise used for profit. All rights regarding the use and ownership of this software shall at all times remain with the author, who does not guarantee the accuracy or reliabilty of this software and who will not accept any liability for its use. This software may not be copied or distributed without the inclusion of the above copyright notice. January 31st 1984 *************************************************************************/ /************************************************************************* Program : CAM Module : IP1.C Author : Nick de Smith November/December 1982 Description : More input utilities for the object module dis- assembler. This bunch is for the code generation stuff. *************************************************************************/ #define MODULE #include #include "cam.h" /************************************************************************* * * * g e t _ i t e m * --------------- * * Get the next data item from the stack, if there is any on it * else from the input file. Return the flags as set. This is the * only function that you can call to get data from the object file. * it will return the next item from a text record, be it byte, word * or whatever. Its up to the caller to determine what to do with * the the item by looking at the flags. * *************************************************************************/ global get_item(d_ptr) register DATA_PTR d_ptr; { return(stack_p ? off_stack(d_ptr) : get_data(d_ptr)); } /************************************************************************* * * * g e t _ d a t a * --------------- * * Get the next data item from the input file. Return flags. * *************************************************************************/ local get_data(d_ptr) register DATA_PTR d_ptr; { register int flags; register int byte; byte = FALSE; for (;;) { if (eom) return (A_EOM); if ((flags = b_current->b_flags) == R_LMOD) return (A_LMOD); if (flags == R_LDEF) return (A_LDEF); if (b_current->b_left) { if (flags & R_RELA && b_current->b_next == r_disp) { if (r_byte) byte = TRUE; r_reld(d_ptr); } if (seg_ptr->p_dot & 1 || b_current->b_left == 1 || (flags & R_RELA && (b_current->b_next + 1) == r_disp)) byte = TRUE; if (byte) { d_ptr->d_value = next_byte(b_current); seg_ptr->p_dot++; return (d_ptr->d_flags |= A_DATA | A_VALID | A_B); } d_ptr->d_value = next_two_bytes(b_current); seg_ptr->p_dot += 2; return (d_ptr->d_flags |= A_DATA | A_VALID); } if (get_text() == R_EOM) eom = TRUE; } } /************************************************************************* * * * r _ r e l d * ----------- * * Evaluate a relocation directory entry for the current data * element. * *************************************************************************/ local r_reld(d_ptr) register DATA_PTR d_ptr; { int name[2]; int value; SYMBOL_PTR lookup(); char *radmin(); d_ptr->d_flags |= A_RELA; d_ptr->d_text[0] = '\0'; switch (r_command) { case T_IREL: value = next_two_bytes(b_other); if (pass == 3) { if (value == seg_ptr->p_dot) { buff[0] = '.'; buff[1] = '\0'; } else radmin((lookup(seg_cur, value))->s_name); cpystr(d_ptr->d_text, buff); } else if (value != seg_ptr->p_dot) insert(seg_cur, value, name, S_WEAK | S_DREF | S_EXT); d_ptr->d_flags |= A_R; break; case T_IDREL: value = next_two_bytes(b_other); if (pass == 3) sprintf(d_ptr->d_text, "%o", value); d_ptr->d_flags |= A_R; break; case T_GREL: case T_GDREL: name[0] = next_two_bytes(b_other); name[1] = next_two_bytes(b_other); if (pass == 3) cpystr(d_ptr->d_text, radmin(name)); d_ptr->d_flags |= A_G; break; case T_GAREL: case T_GADREL: name[0] = next_two_bytes(b_other); name[1] = next_two_bytes(b_other); value = next_two_bytes(b_other); if (pass == 3) { if (value) sprintf(d_ptr->d_text, "%s+%o", radmin(name), value); else cpystr(d_ptr->d_text, radmin(name)); } d_ptr->d_flags |= A_G; break; case T_LDEF: case T_LMOD: bug("LDEF/LMOD when not expected"); case T_LIMIT: d_ptr->d_flags |= A_LIMIT; break; case T_PREL: case T_PDREL: name[0] = next_two_bytes(b_other); name[1] = next_two_bytes(b_other); if (pass == 3) cpystr(d_ptr->d_text, radmin((lookup(find(name), 0))->s_name)); else insert(find(name), 0, name, S_WEAK | S_DREF | S_EXT); d_ptr->d_flags |= A_R; break; case T_PAREL: case T_PADREL: name[0] = next_two_bytes(b_other); name[1] = next_two_bytes(b_other); value = next_two_bytes(b_other); if (pass == 3) cpystr(d_ptr->d_text, radmin((lookup(find(name), value))->s_name)); else insert(find(name), value, name, S_WEAK | S_DREF | S_EXT); d_ptr->d_flags |= A_R; break; case T_CREL: eval_crel(d_ptr); d_ptr->d_flags |= A_C; break; case T_RLREL: warn("Reslib relocation detected\n"); value = next_two_bytes(b_other); if (pass == 3) { if (value) sprintf(d_ptr->d_text, "{task/lib base}+%o", value); else cpystr(d_ptr->d_text, "{task/lib base}"); } d_ptr->d_flags |= A_R; break; default: bug("Strange relocation entry, type %06o", r_command); } r_next(b_other); } /************************************************************************* * * * e v a l _ c r e l * ----------------- * * Evaluate a complex relocation RLD entry. Note that there is a * nasty hack in here. Because I use struct DATA for everything, the * 'dot' has a spare 'd_text[]' which was just going to waste. In * order to evaluate a CREL expression a scratch buffer is needed * to build strings, and wbuf can't be used as it may already contain * some valid argument, so I used dot.d_text[], YUK! * *************************************************************************/ local eval_crel(d_ptr) register DATA_PTR d_ptr; { register int type; register char *temp; int value, seg, offset, name[2]; SYMBOL_PTR lookup(); char *radmin(); c_sp = 0; while ((type = next_byte(b_other)) != C_STORE && type != C_DSTORE) { switch (type) { case C_NOP: break; case C_PLUS: case C_MINUS: case C_MUL: case C_DIV: case C_AND: case C_OR: if (pass != 3) { c_stack[--c_sp - 1].c_prio = comp_prio[type]; break; } temp = cpystr(dot.d_text, c_stack[c_sp -= 2].c_text); temp = cpystr(temp, comp_text[type]); if (comp_prio[type] >= c_stack[++c_sp].c_prio) *temp++ = '<'; temp = cpystr(temp, c_stack[c_sp].c_text); if (comp_prio[type] >= c_stack[c_sp--].c_prio) *temp++ = '>'; *temp = '\0'; cpystr(c_stack[c_sp].c_text, dot.d_text); c_stack[c_sp++].c_prio = comp_prio[type]; break; case C_UMINUS: case C_UCOMP: if (pass != 3) { c_stack[c_sp - 1].c_prio = comp_prio[type]; break; } temp = cpystr(dot.d_text, comp_text[type]); if (comp_prio[type] > c_stack[--c_sp].c_prio) *temp++ = '<'; temp = cpystr(temp, c_stack[c_sp].c_text); if (comp_prio[type] > c_stack[c_sp].c_prio) *temp++ = '>'; *temp = '\0'; cpystr(c_stack[c_sp].c_text, dot.d_text); c_stack[c_sp++].c_prio = comp_prio[type]; break; case C_FGLOB: name_text(b_other); if (pass == 3) cpystr(c_stack[c_sp].c_text, buff); c_stack[c_sp++].c_prio = 10; break; case C_FREL: seg = next_byte(b_other); offset = next_two_bytes(b_other); value = (seg == seg_cur && offset == seg_ptr->p_dot); if (pass == 3) { if (value) { buff[0] = '.'; buff[1] = '\0'; } else radmin((lookup(seg, offset))->s_name); cpystr(c_stack[c_sp].c_text, buff); } else if (!value) insert(seg, offset, name, S_WEAK | S_DREF | S_EXT); c_stack[c_sp++].c_prio = 10; break; case C_FCONST: value = next_two_bytes(b_other); if (pass == 3) sprintf(c_stack[c_sp].c_text, "%o", value); c_stack[c_sp++].c_prio = 10; break; case C_FRB: warn("Complex reference to reslib/task base\n"); if (pass == 3) cpystr(c_stack[c_sp].c_text, "{reslib/task base}"); c_stack[c_sp++].c_prio = 10; break; default: bug("Bad complex relocation entry, %06o", type); } } if (c_sp != 1) bug("Invalid CREL RPN expression"); if (pass == 3) cpystr(d_ptr->d_text, c_stack[0].c_text); } /************************************************************************* * * * g e t _ t e x t * --------------- * * Find the next text record. * *************************************************************************/ local get_text() { if (b_current->b_flags == R_LDEF) return (R_LDEF); if (b_current->b_flags == R_LMOD) return (R_LMOD); b_current->b_flags = R_JUNK; b_switch(); switch (b_current->b_flags & 0377) { case R_EOM: return (R_EOM); case R_LDEF: return (R_LDEF); case R_LMOD: return (R_LMOD); case R_JUNK: return (r_junk()); case R_TEXT: return (r_text()); default: bug("Strange buffer type, %06o, in GET_TEXT", b_current->b_flags); } } /************************************************************************* * * * r _ j u n k * ----------- * * Deal with a junk current buffer. * *************************************************************************/ local r_junk() { register int *flags; flags = &(b_current->b_flags); do { read_record(b_current); switch (next_word(b_current)) { case T_TEXT: *flags = R_TEXT; return (r_text()); case T_RELD: if (r_next(b_current) != R_LMOD && *flags != R_LDEF) bug("Unexpected relocation record"); break; case T_EOM: *flags = R_EOM; break; default: *flags = R_JUNK; break; } } while (*flags == R_JUNK); return (*flags); } /************************************************************************* * * * r _ t e x t * ----------- * * Deal with a text record. Check the next record to see if it * might be a relocation record which could affect this text record. * Note that a relocation record containing just LDEF and LMOD type * entries might crop up, so r_next() checks for this. * *************************************************************************/ local r_text() { int load; if ((load = next_word(b_current)) != seg_ptr->p_dot) if (i_flag) warn("Load address mis-match, is %06o, should be %06o\n", load, seg_ptr->p_dot); else bug("Load address mis-match, is %06o, should be %06o", load, seg_ptr->p_dot); r_other(); return (b_current->b_flags); } /************************************************************************* * * * r _ n e x t * ----------- * * Get the next relocation entry from the specified buffer and * change the buffer characteristics if needs be. Note that this * function may recurse when dealing with relocation records in * b_other. This was introduced to deal with people who want to * dis-assemble .STB files, as TKB produces funny object modules * for these. Try CAM on RMSRES.STB one day! * *************************************************************************/ global r_next(b_ptr) register BUFFER_PTR b_ptr; { if (!(b_ptr->b_left)) { b_ptr->b_flags = R_JUNK; return (b_ptr == b_other ? r_other() : R_JUNK); } r_byte = FALSE; if ((r_command = next_byte(b_ptr)) & 0200) { r_byte = TRUE; r_command &= 0177; } r_disp = next_byte(b_ptr); if (r_command == T_LMOD) return (b_ptr->b_flags = R_LMOD); if (r_command == T_LDEF) return (b_ptr->b_flags = R_LDEF); return (b_ptr->b_flags = R_RELD); } /************************************************************************* * * * r _ o t h e r * ------------- * * Read a record into the 'other' buffer until we get something * meaningful. ie. ignore all GSD/EGSD/ISN type entries. * *************************************************************************/ local r_other() { register int *flags; flags = &(b_other->b_flags); b_current->b_flags &= ~R_RELA; do { read_record(b_other); switch (next_word(b_other)) { case T_TEXT: *flags = R_TEXT; break; case T_RELD: if (r_next(b_other) == R_RELD) b_current->b_flags |= R_RELA; break; case T_EOM: *flags = R_EOM; break; default: *flags = R_JUNK; break; } } while (*flags == R_JUNK); return (*flags); } /************************************************************************* * * * o n _ s t a c k * --------------- * * Stack the data item pointed to. Note that only valid data items * are stacked. Note also that once the item is stacked, the data * structure it was taken from is marked as being unused. * This routine also adjusts the 'pc'. * *************************************************************************/ global on_stack(d_ptr) register DATA_PTR d_ptr; { register DATA_PTR s_ptr; register int flags; if (!(d_ptr->d_flags & A_VALID)) return; if (stack_p >= MAX_STACK) bug("Stack overflow"); s_ptr = &stack[stack_p++]; s_ptr->d_flags = (flags = d_ptr->d_flags); s_ptr->d_value = d_ptr->d_value; seg_ptr->p_dot--; if (!(flags & A_B)) seg_ptr->p_dot--; if (flags & A_RELA) cpystr(s_ptr->d_text, d_ptr->d_text); d_ptr->d_flags &= ~(A_VALID | A_RELA); } /************************************************************************* * * * o f f _ s t a c k * ----------------- * * Get the last stacked item. Return the flags. This routine also * adjusts the 'pc'. * *************************************************************************/ global off_stack(d_ptr) register DATA_PTR d_ptr; { register DATA_PTR s_ptr; register int flags; if (stack_p <= 0) bug("Stack underflow"); s_ptr = &stack[--stack_p]; d_ptr->d_flags = (flags = s_ptr->d_flags); d_ptr->d_value = s_ptr->d_value; seg_ptr->p_dot++; if (!(flags & A_B)) seg_ptr->p_dot++; if (flags & A_RELA) cpystr(d_ptr->d_text, s_ptr->d_text); return (flags); }