📄 tc-tahoe.c
字号:
bit 4 as extern and the last nibble as 'undefined'. */#if commentvoidmd_ri_to_chars (ri_p, ri) struct relocation_info *ri_p, ri;{ byte the_bytes[sizeof (struct relocation_info)]; /* The reason I can't just encode these directly into ri_p is that ri_p may point to ri. */ /* This is easy */ md_number_to_chars (the_bytes, ri.r_address, sizeof (ri.r_address)); /* now the fun stuff */ the_bytes[4] = (ri.r_symbolnum >> 16) & 0x0ff; the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff; the_bytes[6] = ri.r_symbolnum & 0x0ff; the_bytes[7] = (((ri.r_extern << 4) & 0x10) | ((ri.r_length << 5) & 0x60) | ((ri.r_pcrel << 7) & 0x80)) & 0xf0; bcopy (the_bytes, (char *) ri_p, sizeof (struct relocation_info));}#endif /* comment *//* Put the bits in an order that a tahoe will understand, despite the ordering of the native machine. On Tahoe: first 4 bytes are normal unsigned big endian long, next three bytes are symbolnum, in kind of 3 byte big endian (least sig. byte last). The last byte is broken up with bit 7 as pcrel, bits 6 & 5 as length, bit 4 as extern and the last nibble as 'undefined'. */voidtc_aout_fix_to_chars (where, fixP, segment_address_in_file) char *where; fixS *fixP; relax_addressT segment_address_in_file;{ long r_symbolnum; know (fixP->fx_addsy != NULL); md_number_to_chars (where, fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file, 4); r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) ? S_GET_TYPE (fixP->fx_addsy) : fixP->fx_addsy->sy_number); where[4] = (r_symbolnum >> 16) & 0x0ff; where[5] = (r_symbolnum >> 8) & 0x0ff; where[6] = r_symbolnum & 0x0ff; where[7] = (((is_pcrel (fixP) << 7) & 0x80) | ((((fixP->fx_type == FX_8 || fixP->fx_type == FX_PCREL8 ? 0 : (fixP->fx_type == FX_16 || fixP->fx_type == FX_PCREL16 ? 1 : (fixP->fx_type == FX_32 || fixP->fx_type == FX_PCREL32 ? 2 : 42)))) << 5) & 0x60) | ((!S_IS_DEFINED (fixP->fx_addsy) << 4) & 0x10));}/* Relocate byte stuff *//* This is for broken word. */const int md_short_jump_size = 3;voidmd_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; addressT from_addr, to_addr; fragS *frag; symbolS *to_symbol;{ valueT offset; offset = to_addr - (from_addr + 1); *ptr++ = TAHOE_BRW; md_number_to_chars (ptr, offset, 2);}const int md_long_jump_size = 6;const int md_reloc_size = 8; /* Size of relocation record */voidmd_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) char *ptr; addressT from_addr, to_addr; fragS *frag; symbolS *to_symbol;{ valueT offset; offset = to_addr - (from_addr + 4); *ptr++ = TAHOE_JMP; *ptr++ = TAHOE_PC_REL_LONG; md_number_to_chars (ptr, offset, 4);}/* md_estimate_size_before_relax(), called just before relax(). Any symbol that is now undefined will not become defined. Return the correct fr_subtype in the frag and the growth beyond fr_fix. */intmd_estimate_size_before_relax (fragP, segment_type) register fragS *fragP; segT segment_type; /* N_DATA or N_TEXT. */{ if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF) { if (S_GET_SEGMENT (fragP->fr_symbol) != segment) { /* Non-relaxable cases. */ char *p; int old_fr_fix; old_fr_fix = fragP->fr_fix; p = fragP->fr_literal + old_fr_fix; switch (RELAX_STATE (fragP->fr_subtype)) { case STATE_PC_RELATIVE: *p |= TAHOE_PC_OR_LONG; /* We now know how big it will be, one long word. */ fragP->fr_fix += 1 + 4; fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol, fragP->fr_offset, FX_PCREL32, NULL); break; case STATE_CONDITIONAL_BRANCH: *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */ *p++ = 6; *p++ = TAHOE_JMP; *p++ = TAHOE_PC_REL_LONG; fragP->fr_fix += 1 + 1 + 1 + 4; fix_new (fragP, old_fr_fix + 3, fragP->fr_symbol, fragP->fr_offset, FX_PCREL32, NULL); break; case STATE_BIG_REV_BRANCH: *fragP->fr_opcode ^= 0x10; /* Reverse sense of branch. */ *p++ = 0; *p++ = 6; *p++ = TAHOE_JMP; *p++ = TAHOE_PC_REL_LONG; fragP->fr_fix += 2 + 2 + 4; fix_new (fragP, old_fr_fix + 4, fragP->fr_symbol, fragP->fr_offset, FX_PCREL32, NULL); break; case STATE_BIG_NON_REV_BRANCH: *p++ = 2; *p++ = 0; *p++ = TAHOE_BRB; *p++ = 6; *p++ = TAHOE_JMP; *p++ = TAHOE_PC_REL_LONG; fragP->fr_fix += 2 + 2 + 2 + 4; fix_new (fragP, old_fr_fix + 6, fragP->fr_symbol, fragP->fr_offset, FX_PCREL32, NULL); break; case STATE_ALWAYS_BRANCH: *fragP->fr_opcode = TAHOE_JMP; *p++ = TAHOE_PC_REL_LONG; fragP->fr_fix += 1 + 4; fix_new (fragP, old_fr_fix + 1, fragP->fr_symbol, fragP->fr_offset, FX_PCREL32, NULL); break; default: abort (); } frag_wane (fragP); /* Return the growth in the fixed part of the frag. */ return fragP->fr_fix - old_fr_fix; } /* Relaxable cases. Set up the initial guess for the variable part of the frag. */ switch (RELAX_STATE (fragP->fr_subtype)) { case STATE_PC_RELATIVE: fragP->fr_subtype = ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE); break; case STATE_CONDITIONAL_BRANCH: fragP->fr_subtype = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE); break; case STATE_BIG_REV_BRANCH: fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD); break; case STATE_BIG_NON_REV_BRANCH: fragP->fr_subtype = ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD); break; case STATE_ALWAYS_BRANCH: fragP->fr_subtype = ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE); break; } } if (fragP->fr_subtype >= sizeof (md_relax_table) / sizeof (md_relax_table[0])) abort (); /* Return the size of the variable part of the frag. */ return md_relax_table[fragP->fr_subtype].rlx_length;}/* * md_convert_frag(); * * Called after relax() is finished. * In: Address of frag. * fr_type == rs_machine_dependent. * fr_subtype is what the address relaxed to. * * Out: Any fixSs and constants are set up. * Caller will turn frag into a ".space 0". */voidmd_convert_frag (headers, seg, fragP) object_headers *headers; segT seg; register fragS *fragP;{ register char *addressP; /* -> _var to change. */ register char *opcodeP; /* -> opcode char(s) to change. */ register short int extension = 0; /* Size of relaxed address. Added to fr_fix: incl. ALL var chars. */ register symbolS *symbolP; register long int where; register long int address_of_var; /* Where, in file space, is _var of *fragP? */ register long int target_address; /* Where, in file space, does addr point? */ know (fragP->fr_type == rs_machine_dependent); where = fragP->fr_fix; addressP = fragP->fr_literal + where; opcodeP = fragP->fr_opcode; symbolP = fragP->fr_symbol; know (symbolP); target_address = S_GET_VALUE (symbolP) + fragP->fr_offset; address_of_var = fragP->fr_address + where; switch (fragP->fr_subtype) { case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_BYTE): /* *addressP holds the registers number, plus 0x10, if it's deferred mode. To set up the right mode, just OR the size of this displacement */ /* Byte displacement. */ *addressP++ |= TAHOE_PC_OR_BYTE; *addressP = target_address - (address_of_var + 2); extension = 2; break; case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_WORD): /* Word displacement. */ *addressP++ |= TAHOE_PC_OR_WORD; md_number_to_chars (addressP, target_address - (address_of_var + 3), 2); extension = 3; break; case ENCODE_RELAX (STATE_PC_RELATIVE, STATE_LONG): /* Long word displacement. */ *addressP++ |= TAHOE_PC_OR_LONG; md_number_to_chars (addressP, target_address - (address_of_var + 5), 4); extension = 5; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE): *addressP = target_address - (address_of_var + 1); extension = 1; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD): *opcodeP ^= 0x10; /* Reverse sense of test. */ *addressP++ = 3; /* Jump over word branch */ *addressP++ = TAHOE_BRW; md_number_to_chars (addressP, target_address - (address_of_var + 4), 2); extension = 4; break; case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_LONG): *opcodeP ^= 0x10; /* Reverse sense of test. */ *addressP++ = 6; *addressP++ = TAHOE_JMP; *addressP++ = TAHOE_PC_REL_LONG; md_number_to_chars (addressP, target_address, 4); extension = 7; break; case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_BYTE): *addressP = target_address - (address_of_var + 1); extension = 1; break; case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_WORD): *opcodeP = TAHOE_BRW; md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); extension = 2; break; case ENCODE_RELAX (STATE_ALWAYS_BRANCH, STATE_LONG): *opcodeP = TAHOE_JMP; *addressP++ = TAHOE_PC_REL_LONG; md_number_to_chars (addressP, target_address - (address_of_var + 5), 4); extension = 5; break; case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_WORD): md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); extension = 2; break; case ENCODE_RELAX (STATE_BIG_REV_BRANCH, STATE_LONG): *opcodeP ^= 0x10; *addressP++ = 0; *addressP++ = 6; *addressP++ = TAHOE_JMP; *addressP++ = TAHOE_PC_REL_LONG; md_number_to_chars (addressP, target_address, 4); extension = 8; break; case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_WORD): md_number_to_chars (addressP, target_address - (address_of_var + 2), 2); extension = 2; break; case ENCODE_RELAX (STATE_BIG_NON_REV_BRANCH, STATE_LONG): *addressP++ = 0; *addressP++ = 2; *addressP++ = TAHOE_BRB; *addressP++ = 6; *addressP++ = TAHOE_JMP; *addressP++ = TAHOE_PC_REL_LONG; md_number_to_chars (addressP, target_address, 4); extension = 10; break; default: BAD_CASE (fragP->fr_subtype); break; } fragP->fr_fix += extension;} /* md_convert_frag *//* This is the stuff for md_assemble. */#define FP_REG 13#define SP_REG 14#define PC_REG 15#define BIGGESTREG PC_REG/* * Parse the string pointed to by START * If it represents a valid register, point START to the character after * the last valid register char, and return the register number (0-15). * If invalid, leave START alone, return -1. * The format has to be exact. I don't do things like eat leading zeros * or the like. * Note: This doesn't check for the next character in the string making * this invalid. Ex: R123 would return 12, it's the callers job to check * what start is point to apon return. * * Valid registers are R1-R15, %1-%15, FP (13), SP (14), PC (15) * Case doesn't matter. */inttahoe_reg_parse (start) char **start; /* A pointer to the string to parse. */{ register char *regpoint = *start; register int regnum = -1; switch (*regpoint++) { case '%': /* Registers can start with a %, R or r, and then a number. */ case 'R': case 'r': if (isdigit (*regpoint)) { /* Got the first digit. */ regnum = *regpoint++ - '0'; if ((regnum == 1) && isdigit (*regpoint)) { /* Its a two digit number. */ regnum = 10 + (*regpoint++ - '0'); if (regnum > BIGGESTREG) { /* Number too big? */ regnum = -1; } } } break; case 'F': /* Is it the FP */ case 'f': switch (*regpoint++) { case 'p': case 'P': regnum = FP_REG; } break; case 's': /* How about the SP */ case 'S': switch (*regpoint++) { case 'p': case 'P': regnum = SP_REG; } break; case 'p': /* OR the PC even */ case 'P': switch (*regpoint++) { case 'c': case 'C': regnum = PC_REG; } break; } if (regnum != -1) { /* No error, so move string pointer */ *start = regpoint; } return regnum; /* Return results */} /* tahoe_reg_parse *//* * This chops up an operand and figures out its modes and stuff. * It's a little touchy about extra characters. * Optex to start with one extra character so it can be overwritten for * the backward part of the parsing. * You can't put a bunch of extra characters in side to * make the command look cute. ie: * foo ( r1 ) [ r0 ] * If you like doing a lot of typing, try COBOL! * Actually, this parser is a little weak all around. It's designed to be * used with compliers, so I emphisise correct decoding of valid code quickly * rather that catching every possable error. * Note: This uses the expression function, so save input_line_pointer before * calling. * * Sperry defines the semantics of address modes (and values) * by a two-letter code, explained here. * * letter 1: access type * * a address calculation - no data access, registers forbidden * b branch displacement * m read - let go of bus - write back "modify" * r read * w write * v bit field address: like 'a' but registers are OK * * letter 2: data type (i.e. width, alignment) * * b byte * w word * l longword * q quadword (Even regs < 14 allowed) (if 12, you get a warning) * - unconditional synthetic jbr operand * ? simple synthetic reversable branch operand * ! complex synthetic reversable branch operand * : complex synthetic non-reversable branch operand * * The '-?!:' letter 2's are not for external consumption. They are used * by GAS for psuedo ops relaxing code. * * After parsing topP has: * * top_ndx: -1, or the index register. eg 7=[R7] * top_reg: -1, or register number. eg 7 = R7 or (R7) * top_mode: The addressing mode byte. This byte, defines which of * the 11 modes opcode is. * top_access: Access type wanted for this opperand 'b'branch ' ' * no-instruction 'amrvw' * top_width: Operand width expected, one of "bwlq?-:!" * exp_of_operand: The expression as parsed by expression() * top_dispsize: Number of bytes in the displacement if we can figure it * out and it's relavent. * * Need syntax checks built. */voidtip_op (optex, topP) char *optex; /* The users text input, with one leading character */ struct top *topP; /* The tahoe instruction with some fields already set: in: access, width out: ndx, reg, mode, error, dispsize */{ int mode = 0; /* This operand's mode. */ char segfault = *optex; /* To keep the back parsing from freaking. */ char *point = optex + 1; /* Parsing from front to back. */ char *end; /* Parsing from back to front. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -