📄 tc-i370.c
字号:
literals[next_literal_pool_place].exp = *exx; literals[next_literal_pool_place].size = sz; literals[next_literal_pool_place].offset = offset_in_pool; if (name) { literals[next_literal_pool_place].sym_name = strdup (name); } else { literals[next_literal_pool_place].sym_name = NULL; } next_literal_pool_place++; } /* ???_poolP points to the begining of the literal pool. * X_add_number is the offset from the begining of the * literal pool to this expr minus the location of the most * recent .using directive. Thus, the grand total value of the * expression is the distance from .using to the literal. */ if (8 == sz) exx->X_add_symbol = longlong_poolP; else if (4 == sz) exx->X_add_symbol = word_poolP; else if (2 == sz) exx->X_add_symbol = short_poolP; else if (1 == sz) exx->X_add_symbol = byte_poolP; exx->X_add_number = offset_in_pool; exx->X_op_symbol = NULL; /* If the user has set up a base reg in another section, * use that; otherwise use the text section. */ if (0 < i370_using_other_regno) { i370_make_relative (exx, &i370_using_other_baseaddr); } else { i370_make_relative (exx, &i370_using_text_baseaddr); }}/* The symbol setup for the literal pool is done in two steps. First, * a symbol that represents the start of the literal pool is created, * above, in the add_to_pool() routine. This sym ???_poolP. * However, we don't know what fragment its in until a bit later. * So we defer the frag_now thing, and the symbol name, until .ltorg time *//* Can't use symbol_new here, so have to create a symbol and then at a later date assign it a value. Thats what these functions do */static voidsymbol_locate (symbolP, name, segment, valu, frag) symbolS *symbolP; CONST char *name; /* It is copied, the caller can modify */ segT segment; /* Segment identifier (SEG_<something>) */ valueT valu; /* Symbol value */ fragS *frag; /* Associated fragment */{ size_t name_length; char *preserved_copy_of_name; name_length = strlen (name) + 1; /* +1 for \0 */ obstack_grow (¬es, name, name_length); preserved_copy_of_name = obstack_finish (¬es); S_SET_NAME (symbolP, preserved_copy_of_name); S_SET_SEGMENT (symbolP, segment); S_SET_VALUE (symbolP, valu); symbol_clear_list_pointers(symbolP); symbol_set_frag (symbolP, frag); /* * Link to end of symbol chain. */ { extern int symbol_table_frozen; if (symbol_table_frozen) abort (); } symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); obj_symbol_new_hook (symbolP);#ifdef tc_symbol_new_hook tc_symbol_new_hook (symbolP);#endif#define DEBUG_SYMS#ifdef DEBUG_SYMS verify_symbol_chain(symbol_rootP, symbol_lastP);#endif /* DEBUG_SYMS */}/* i370_addr_offset() will convert operand expressions * that appear to be absolute into thier base-register * relative form. These expressions come in two types: * * (1) of the form "* + const" * where "*" means * relative offset since the last using * i.e. "*" means ".-using_baseaddr" * * (2) labels, which are never absolute, but are always * relative to the last "using". Anything with an alpha * character is considered to be a label (since symbols * can never be operands), and since we've already handled * register operands. For example, "BL .L33" branch low * to .L33 RX form insn frequently terminates for-loops, */static booleani370_addr_offset (expressionS *exx){ char *dot, *lab; int islabel = 0; int all_digits = 0; /* search for a label; anything with an alpha char will do */ /* local labels consist of N digits followed by either b or f */ lab = input_line_pointer; while (*lab && (',' != *lab) && ('(' != *lab)) { if (isdigit(*lab)) { all_digits = 1; } else if (isalpha(*lab)) { if (!all_digits) { islabel = 1; break; } else if (('f' == *lab) || ('b' == *lab)) { islabel = 1; break; } if (all_digits) break; } else if ('.' != *lab) break; ++lab; } /* See if operand has a * in it */ dot = strchr (input_line_pointer, '*'); if (!dot && !islabel) return false; /* replace * with . and let expr munch on it. */ if (dot) *dot = '.'; expression (exx); /* OK, now we have to subtract the "using" location */ /* normally branches appear in the text section only... */ if (0 == strncmp (now_seg->name, ".text", 5) || 0 > i370_using_other_regno) { i370_make_relative (exx, &i370_using_text_baseaddr); } else { i370_make_relative (exx, &i370_using_other_baseaddr); } /* put the * back */ if (dot) *dot = '*'; return true;}/* handle address constants of various sorts *//* The currently supported types are * =A(some_symb) * =V(some_extern) * =X'deadbeef' hexadecimal * =F'1234' 32-bit const int * =H'1234' 16-bit const int */static booleani370_addr_cons (expressionS *exp){ char *name; char *sym_name, delim; int name_len; int hex_len=0; int cons_len=0; name = input_line_pointer; sym_name = input_line_pointer; /* Find the spelling of the operand */ if (name[0] == '=' && isalpha (name[1])) { name = ++input_line_pointer; } else { return false; } switch (name[0]) { case 'A': case 'V': /* A == address-of */ /* V == extern */ ++input_line_pointer; expression (exp); /* we use a simple string name to collapse together * multiple refrences to the same address literal */ name_len = strcspn (sym_name, ", "); delim = *(sym_name + name_len); *(sym_name + name_len) = 0x0; add_to_lit_pool (exp, sym_name, 4); *(sym_name + name_len) = delim; break; case 'H': case 'F': case 'X': case 'E': /* single-precision float point */ case 'D': /* double-precision float point */ /* H == 16-bit fixed-point const; expression must be const */ /* F == fixed-point const; expression must be const */ /* X == fixed-point const; expression must be const */ if ('H' == name[0]) cons_len = 2; else if ('F' == name[0]) cons_len = 4; else if ('X' == name[0]) cons_len = -1; else if ('E' == name[0]) cons_len = 4; else if ('D' == name[0]) cons_len = 8; /* extract length, if it is present; hack alert -- assume single-digit * length */ if ('L' == name[1]) { cons_len = name[2] - '0'; /* should work for ascii and ebcdic */ input_line_pointer += 2; } ++input_line_pointer; /* get rid of pesky quotes */ if ('\'' == *input_line_pointer) { char * close; ++input_line_pointer; close = strchr (input_line_pointer, '\''); if (close) *close= ' '; else as_bad ("missing end-quote"); } if ('\"' == *input_line_pointer) { char * close; ++input_line_pointer; close = strchr (input_line_pointer, '\"'); if (close) *close= ' '; else as_bad ("missing end-quote"); } if (('X' == name[0]) || ('E' == name[0]) || ('D' == name[0])) { char tmp[50]; char *save; /* The length of hex constants is specified directly with L, * or implied through the number of hex digits. For example: * =X'AB' one byte * =X'abcd' two bytes * =X'000000AB' four bytes * =XL4'AB' four bytes, left-padded withn zero */ if (('X' == name[0]) && (0 > cons_len)) { save = input_line_pointer; while (*save) { if (isxdigit(*save)) hex_len++; save++; } cons_len = (hex_len+1) /2; } /* I beleive this works even for =XL8'dada0000beeebaaa' * which should parse out to X_op == O_big * Note that floats and doubles get represented as * 0d3.14159265358979 or 0f 2.7 */ tmp[0] = '0'; tmp[1] = name[0]; tmp[2] = 0; strcat (tmp, input_line_pointer); save = input_line_pointer; input_line_pointer = tmp; expression (exp); input_line_pointer = save + (input_line_pointer-tmp-2); /* fix up lengths for floats and doubles */ if (O_big == exp->X_op) { exp->X_add_number = cons_len / CHARS_PER_LITTLENUM; } } else { expression (exp); } /* O_big occurs when more than 4 bytes worth gets parsed */ if ((exp->X_op != O_constant) && (exp->X_op != O_big)) { as_bad ("expression not a constant"); return false; } add_to_lit_pool (exp, 0x0, cons_len); break; default: as_bad ("Unknown/unsupported address literal type"); return false; } return true;}/* Dump the contents of the literal pool that we've accumulated so far. * This aligns the pool to the size of the largest literal in the pool. */static voidi370_ltorg (ignore) int ignore;{ int litsize; int lit_count = 0; int biggest_literal_size = 0; int biggest_align = 0; char pool_name[20]; if (strncmp (now_seg->name, ".text", 5)) { if (i370_other_section == undefined_section) { as_bad (".ltorg without prior .using in section %s", now_seg->name); } if (i370_other_section != now_seg) { as_bad (".ltorg in section %s paired to .using in section %s", now_seg->name, i370_other_section->name); } } if (! longlong_poolP && ! word_poolP && ! short_poolP && ! byte_poolP) { /* Nothing to do */ /* as_tsktsk ("Nothing to put in the pool\n"); */ return; } /* find largest literal .. 2 4 or 8 */ lit_count = 0; while (lit_count < next_literal_pool_place) { if (biggest_literal_size < literals[lit_count].size) biggest_literal_size = literals[lit_count].size; lit_count ++; } if (1 == biggest_literal_size) biggest_align = 0; else if (2 == biggest_literal_size) biggest_align = 1; else if (4 == biggest_literal_size) biggest_align = 2; else if (8 == biggest_literal_size) biggest_align = 3; else as_bad ("bad alignment of %d bytes in literal pool", biggest_literal_size); if (0 == biggest_align) biggest_align = 1; /* Align pool for short, word, double word accesses */ frag_align (biggest_align, 0, 0); record_alignment (now_seg, biggest_align); /* Note that the gas listing will print only the first five * entries in the pool .... wonder how to make it print more ... */ /* output largest literals first, then the smaller ones. */ for (litsize=8; litsize; litsize /=2) { symbolS *current_poolP = NULL; switch (litsize) { case 8: current_poolP = longlong_poolP; break; case 4: current_poolP = word_poolP; break; case 2: current_poolP = short_poolP; break; case 1: current_poolP = byte_poolP; break; default: as_bad ("bad literal size\n"); } if (NULL == current_poolP) continue; sprintf (pool_name, ".LITP%01d%06d", litsize, lit_pool_num); symbol_locate (current_poolP, pool_name, now_seg, (valueT) frag_now_fix (), frag_now); symbol_table_insert (current_poolP); lit_count = 0; while (lit_count < next_literal_pool_place) { if (litsize == literals[lit_count].size) {#define EMIT_ADDR_CONS_SYMBOLS#ifdef EMIT_ADDR_CONS_SYMBOLS /* create a bogus symbol, add it to the pool ... * For the most part, I think this is a useless excercise, * except that having these symbol names in the objects * is vaguely useful for debugging ... */ if (literals[lit_count].sym_name) { symbolS * symP = symbol_make_empty(); symbol_locate (symP, literals[lit_count].sym_name, now_seg, (valueT) frag_now_fix (), frag_now); symbol_table_insert (symP); }#endif /* EMIT_ADDR_CONS_SYMBOLS */ emit_expr (&(literals[lit_count].exp), literals[lit_count].size); } lit_count ++; } } next_literal_pool_place = 0; longlong_poolP = NULL; word_poolP = NULL; short_poolP = NULL; byte_poolP = NULL; lit_pool_num++;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -