static void out_inc_line_addr (int line_delta, addressT addr_delta) { int len = size_inc_line_addr (line_delta, addr_delta); emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len); }
static void out_debug_aranges (segT aranges_seg, segT info_seg) { unsigned int addr_size = sizeof_address; addressT size, skip; struct line_seg *s; expressionS expr; char *p; size = 4 + 2 + 4 + 1 + 1; skip = 2 * addr_size - (size & (2 * addr_size - 1)); if (skip == 2 * addr_size) skip = 0; size += skip; for (s = all_segs; s; s = s->next) size += 2 * addr_size; size += 2 * addr_size; subseg_set (aranges_seg, 0); /* Length of the compilation unit. */ out_four (size - 4); /* Version. */ out_two (2); /* Offset to .debug_info. */ /* ??? sizeof_offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4); /* Size of an address (offset portion). */ out_byte (addr_size); /* Size of a segment descriptor. */ out_byte (0); /* Align the header. */ if (skip) frag_align (ffs (2 * addr_size) - 1, 0, 0); for (s = all_segs; s; s = s->next) { fragS *frag; symbolS *beg, *end; frag = first_frag_for_seg (s->seg); beg = symbol_temp_new (s->seg, 0, frag); s->text_start = beg; frag = last_frag_for_seg (s->seg); end = symbol_temp_new (s->seg, get_frag_fix (frag), frag); s->text_end = end; expr.X_op = O_symbol; expr.X_add_symbol = beg; expr.X_add_number = 0; emit_expr (&expr, addr_size); expr.X_op = O_subtract; expr.X_add_symbol = end; expr.X_op_symbol = beg; expr.X_add_number = 0; emit_expr (&expr, addr_size); } p = frag_more (2 * addr_size); md_number_to_chars (p, 0, addr_size); md_number_to_chars (p + addr_size, 0, addr_size); }
static inline void out_four (int data) { md_number_to_chars (frag_more (4), data, 4); }
static void out_sleb128 (addressT value) { output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1); }
static void out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg) { char producer[128]; char *comp_dir; expressionS expr; symbolS *info_start; symbolS *info_end; char *p; int len; enum dwarf2_format d2f; int sizeof_offset; subseg_set (info_seg, 0); info_start = symbol_temp_new_now (); info_end = symbol_temp_make (); /* Compilation Unit length. */ expr.X_op = O_subtract; expr.X_add_symbol = info_end; expr.X_op_symbol = info_start; d2f = DWARF2_FORMAT (); if (d2f == dwarf2_format_32bit) { expr.X_add_number = -4; emit_expr (&expr, 4); sizeof_offset = 4; } else if (d2f == dwarf2_format_64bit) { expr.X_add_number = -12; out_four (-1); emit_expr (&expr, 8); sizeof_offset = 8; } else if (d2f == dwarf2_format_64bit_irix) { expr.X_add_number = -8; emit_expr (&expr, 8); sizeof_offset = 8; } else { as_fatal (_("internal error: unknown dwarf2 format")); } /* DWARF version. */ out_two (2); /* .debug_abbrev offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); /* Target address size. */ out_byte (sizeof_address); /* DW_TAG_compile_unit DIE abbrev */ out_uleb128 (1); /* DW_AT_stmt_list */ /* ??? sizeof_offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4); /* These two attributes are emitted if all of the code is contiguous. */ if (all_segs->next == NULL) { /* DW_AT_low_pc */ expr.X_op = O_symbol; expr.X_add_symbol = all_segs->text_start; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); /* DW_AT_high_pc */ expr.X_op = O_symbol; expr.X_add_symbol = all_segs->text_end; expr.X_add_number = 0; emit_expr (&expr, sizeof_address); } else { /* This attribute is emitted if the code is disjoint. */ /* DW_AT_ranges. */ TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset); } /* DW_AT_name. We don't have the actual file name that was present on the command line, so assume files[1] is the main input file. We're not supposed to get called unless at least one line number entry was emitted, so this should always be defined. */ if (!files || files_in_use < 1) abort (); if (files[1].dir) { len = strlen (dirs[files[1].dir]); p = frag_more (len + 1); memcpy (p, dirs[files[1].dir], len); INSERT_DIR_SEPARATOR (p, len); } len = strlen (files[1].filename) + 1; p = frag_more (len); memcpy (p, files[1].filename, len); /* DW_AT_comp_dir */ comp_dir = getpwd (); len = strlen (comp_dir) + 1; p = frag_more (len); memcpy (p, comp_dir, len); /* DW_AT_producer */ sprintf (producer, "GNU AS %s", VERSION); len = strlen (producer) + 1; p = frag_more (len); memcpy (p, producer, len); /* DW_AT_language. Yes, this is probably not really MIPS, but the dwarf2 draft has no standard code for assembler. */ out_two (DW_LANG_Mips_Assembler); symbol_set_value_now (info_end); }
static inline void out_two (int data) { md_number_to_chars (frag_more (2), data, 2); }
static void out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg, segT ranges_seg) { char producer[128]; const char *comp_dir; const char *dirname; expressionS exp; symbolS *info_end; char *p; int len; int sizeof_offset; sizeof_offset = out_header (info_seg, &exp); info_end = exp.X_add_symbol; /* DWARF version. */ out_two (2); /* .debug_abbrev offset */ TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); /* Target address size. */ out_byte (sizeof_address); /* DW_TAG_compile_unit DIE abbrev */ out_uleb128 (1); /* DW_AT_stmt_list */ TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), (DWARF2_FORMAT (line_seg) == dwarf2_format_32bit ? 4 : 8)); /* These two attributes are emitted if all of the code is contiguous. */ if (all_segs->next == NULL) { /* DW_AT_low_pc */ exp.X_op = O_symbol; exp.X_add_symbol = all_segs->text_start; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); /* DW_AT_high_pc */ exp.X_op = O_symbol; exp.X_add_symbol = all_segs->text_end; exp.X_add_number = 0; emit_expr (&exp, sizeof_address); } else { /* This attribute is emitted if the code is disjoint. */ /* DW_AT_ranges. */ TC_DWARF2_EMIT_OFFSET (section_symbol (ranges_seg), sizeof_offset); } /* DW_AT_name. We don't have the actual file name that was present on the command line, so assume files[1] is the main input file. We're not supposed to get called unless at least one line number entry was emitted, so this should always be defined. */ if (files_in_use == 0) abort (); if (files[1].dir) { dirname = remap_debug_filename (dirs[files[1].dir]); len = strlen (dirname); #ifdef TE_VMS /* Already has trailing slash. */ p = frag_more (len); memcpy (p, dirname, len); #else p = frag_more (len + 1); memcpy (p, dirname, len); INSERT_DIR_SEPARATOR (p, len); #endif } len = strlen (files[1].filename) + 1; p = frag_more (len); memcpy (p, files[1].filename, len); /* DW_AT_comp_dir */ comp_dir = remap_debug_filename (getpwd ()); len = strlen (comp_dir) + 1; p = frag_more (len); memcpy (p, comp_dir, len); /* DW_AT_producer */ sprintf (producer, "GNU AS %s", VERSION); len = strlen (producer) + 1; p = frag_more (len); memcpy (p, producer, len); /* DW_AT_language. Yes, this is probably not really MIPS, but the dwarf2 draft has no standard code for assembler. */ out_two (DW_LANG_Mips_Assembler); symbol_set_value_now (info_end); }
void md_assemble (char *str) { char *op_start; char *op_end; moxie_opc_info_t *opcode; char *p; char pend; unsigned short iword = 0; int nlen = 0; /* Drop leading whitespace. */ while (*str == ' ') str++; /* Find the op code end. */ op_start = str; for (op_end = str; *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' '; op_end++) nlen++; pend = *op_end; *op_end = 0; if (nlen == 0) as_bad (_("can't find opcode ")); opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start); *op_end = pend; if (opcode == NULL) { as_bad (_("unknown opcode %s"), op_start); return; } p = frag_more (2); switch (opcode->itype) { case MOXIE_F2_A8V: iword = (1<<15) | (opcode->opcode << 12); while (ISSPACE (*op_end)) op_end++; { expressionS arg; int reg; reg = parse_register_operand (&op_end); iword += (reg << 8); if (*op_end != ',') as_warn (_("expecting comma delimited register operands")); op_end++; op_end = parse_exp_save_ilp (op_end, &arg); fix_new_exp (frag_now, ((p + (target_big_endian ? 1 : 0)) - frag_now->fr_literal), 1, &arg, 0, BFD_RELOC_8); } break; case MOXIE_F1_AB: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { int dest, src; dest = parse_register_operand (&op_end); if (*op_end != ',') as_warn (_("expecting comma delimited register operands")); op_end++; src = parse_register_operand (&op_end); iword += (dest << 4) + src; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); } break; case MOXIE_F1_A4: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { expressionS arg; char *where; int regnum; regnum = parse_register_operand (&op_end); while (ISSPACE (*op_end)) op_end++; iword += (regnum << 4); if (*op_end != ',') { as_bad (_("expecting comma delimited operands")); ignore_rest_of_line (); return; } op_end++; op_end = parse_exp_save_ilp (op_end, &arg); where = frag_more (4); fix_new_exp (frag_now, (where - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } break; case MOXIE_F1_M: case MOXIE_F1_4: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { expressionS arg; char *where; op_end = parse_exp_save_ilp (op_end, &arg); where = frag_more (4); fix_new_exp (frag_now, (where - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } break; case MOXIE_F1_NARG: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); break; case MOXIE_F1_A: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { int reg; reg = parse_register_operand (&op_end); while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); iword += (reg << 4); } break; case MOXIE_F1_ABi: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { int a, b; a = parse_register_operand (&op_end); if (*op_end != ',') as_warn (_("expecting comma delimited register operands")); op_end++; if (*op_end != '(') { as_bad (_("expecting indirect register `($rA)'")); ignore_rest_of_line (); return; } op_end++; b = parse_register_operand (&op_end); if (*op_end != ')') { as_bad (_("missing closing parenthesis")); ignore_rest_of_line (); return; } op_end++; iword += (a << 4) + b; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); } break; case MOXIE_F1_AiB: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { int a, b; if (*op_end != '(') { as_bad (_("expecting indirect register `($rA)'")); ignore_rest_of_line (); return; } op_end++; a = parse_register_operand (&op_end); if (*op_end != ')') { as_bad (_("missing closing parenthesis")); ignore_rest_of_line (); return; } op_end++; if (*op_end != ',') as_warn (_("expecting comma delimited register operands")); op_end++; b = parse_register_operand (&op_end); iword += (a << 4) + b; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); } break; case MOXIE_F1_4A: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { expressionS arg; char *where; int a; op_end = parse_exp_save_ilp (op_end, &arg); where = frag_more (4); fix_new_exp (frag_now, (where - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); if (*op_end != ',') { as_bad (_("expecting comma delimited operands")); ignore_rest_of_line (); return; } op_end++; a = parse_register_operand (&op_end); while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); iword += (a << 4); } break; case MOXIE_F1_ABi2: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { expressionS arg; char *offset; int a, b; a = parse_register_operand (&op_end); while (ISSPACE (*op_end)) op_end++; if (*op_end != ',') { as_bad (_("expecting comma delimited operands")); ignore_rest_of_line (); return; } op_end++; op_end = parse_exp_save_ilp (op_end, &arg); offset = frag_more (2); fix_new_exp (frag_now, (offset - frag_now->fr_literal), 2, &arg, 0, BFD_RELOC_16); if (*op_end != '(') { as_bad (_("expecting indirect register `($rX)'")); ignore_rest_of_line (); return; } op_end++; b = parse_register_operand (&op_end); if (*op_end != ')') { as_bad (_("missing closing parenthesis")); ignore_rest_of_line (); return; } op_end++; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); iword += (a << 4) + b; } break; case MOXIE_F1_AiB2: iword = opcode->opcode << 8; while (ISSPACE (*op_end)) op_end++; { expressionS arg; char *offset; int a, b; op_end = parse_exp_save_ilp (op_end, &arg); offset = frag_more (2); fix_new_exp (frag_now, (offset - frag_now->fr_literal), 2, &arg, 0, BFD_RELOC_16); if (*op_end != '(') { as_bad (_("expecting indirect register `($rX)'")); ignore_rest_of_line (); return; } op_end++; a = parse_register_operand (&op_end); if (*op_end != ')') { as_bad (_("missing closing parenthesis")); ignore_rest_of_line (); return; } op_end++; if (*op_end != ',') { as_bad (_("expecting comma delimited operands")); ignore_rest_of_line (); return; } op_end++; b = parse_register_operand (&op_end); while (ISSPACE (*op_end)) op_end++; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); iword += (a << 4) + b; } break; case MOXIE_F2_NARG: iword = opcode->opcode << 12; while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); break; case MOXIE_F3_PCREL: iword = (3<<14) | (opcode->opcode << 10); while (ISSPACE (*op_end)) op_end++; { expressionS arg; op_end = parse_exp_save_ilp (op_end, &arg); fix_new_exp (frag_now, (p - frag_now->fr_literal), 2, &arg, TRUE, BFD_RELOC_MOXIE_10_PCREL); } break; default: abort (); } md_number_to_chars (p, iword, 2); while (ISSPACE (*op_end)) op_end++; if (*op_end != 0) as_warn (_("extra stuff on line ignored")); if (pending_reloc) as_bad (_("Something forgot to clean up\n")); }
/* Convert the instructions into frags and bytes */ void md_assemble(char *str) { char *op_start; char *op_end; char op_name[10]; const bexkat1_opc_info_t *opcode; char *p; char pend; unsigned int iword; int nlen = 0; int regnum; expressionS arg; int offset; while (*str == ' ') str++; // mark opcode op_start = str; for (op_end = str; *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' '; op_end++) nlen++; pend = *op_end; *op_end = 0; strncpy(op_name, op_start, 10); *op_end = pend; if (nlen == 0) as_bad(_("can't find opcode ")); while (ISSPACE(*op_end)) op_end++; opcode = (bexkat1_opc_info_t *) hash_find(opcode_hash_control, op_name); if (opcode == NULL) { as_bad(_("unknown opcode %s"), op_name); return; } iword = (opcode->type << 28) | (opcode->opcode << 24) | opcode->size; p = frag_more(4); switch (opcode->type) { case BEXKAT1_INH: if (opcode->args == 0) { md_number_to_chars(p, iword, 4); } if (opcode->args == 1) { op_end = parse_exp_save_ilp(op_end, &arg); if (opcode->size) { md_number_to_chars(p, iword, 4); p = frag_more(4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } else { if (arg.X_op != O_constant) { as_bad(_("offset is not a constant expression")); ignore_rest_of_line(); return; } offset = arg.X_add_number; if (offset < -16384 || offset > 16383) { as_bad(_("offset is out of range: %d\n"), offset); ignore_rest_of_line(); return; } md_number_to_chars(p, iword, 4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_BEXKAT1_15); } } break; case BEXKAT1_PUSH: if (opcode->args == 1 && opcode->opcode == 2) // bsr goto branch; if (opcode->args == 1) { if (opcode->size) { op_end = parse_exp_save_ilp(op_end, &arg); md_number_to_chars(p, iword, 4); p = frag_more(4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } else { regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A md_number_to_chars(p, iword, 4); } } if (opcode->args == 2) { if (*op_end != '(') op_end = parse_exp_save_ilp(op_end, &arg); else { // Implicit 0 offset to allow for indirect arg.X_op = O_constant; arg.X_add_number = 0; } if (*op_end != '(') { as_bad(_("missing open paren: %s"), op_end); ignore_rest_of_line(); return; } op_end++; // burn paren while (ISSPACE(*op_end)) op_end++; regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A if (*op_end != ')') { as_bad(_("missing close paren: %s"), op_end); ignore_rest_of_line(); return; } op_end++; if (arg.X_op != O_constant) { as_bad(_("offset is not a constant expression")); ignore_rest_of_line(); return; } offset = arg.X_add_number; if (offset < -16384 || offset > 16383) { as_bad(_("offset is out of range: %d\n"), offset); ignore_rest_of_line(); return; } md_number_to_chars(p, iword, 4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_BEXKAT1_15); } break; case BEXKAT1_POP: if (opcode->args == 0) { md_number_to_chars(p, iword, 4); } if (opcode->args == 1) { regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A md_number_to_chars(p, iword, 4); } break; case BEXKAT1_MOV: if (opcode->opcode == 0) { regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A md_number_to_chars(p, iword, 4); break; } /* __attribute__((fallthrough)); */ case BEXKAT1_CMP: case BEXKAT1_FPU: case BEXKAT1_FP: case BEXKAT1_ALU: case BEXKAT1_INT: case BEXKAT1_INTU: if (opcode->args > 1) { regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A if (*op_end != ',') { as_bad(_("missing comma: %s"), op_end); return; } op_end++; while (ISSPACE(*op_end)) op_end++; } regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 16; // B if (opcode->args > 2) { if (*op_end != ',') { as_bad(_("missing comma: %s"), op_end); return; } op_end++; while (ISSPACE(*op_end)) op_end++; if (opcode->opcode < 8) { regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 12; // C md_number_to_chars(p, iword, 4); } else { op_end = parse_exp_save_ilp(op_end, &arg); if (arg.X_op != O_constant) { as_bad(_("offset is not a constant expression")); ignore_rest_of_line(); return; } offset = arg.X_add_number; if (offset < -16384 || offset > 16383) { as_bad(_("offset is out of range: %d\n"), offset); ignore_rest_of_line(); return; } md_number_to_chars(p, iword, 4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_BEXKAT1_15); } } else { md_number_to_chars(p, iword, 4); } break; branch: case BEXKAT1_BRANCH: md_number_to_chars(p, iword, 4); op_end = parse_exp_save_ilp(op_end, &arg); if (target_big_endian) fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, TRUE, BFD_RELOC_BEXKAT1_15_PCREL); else fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, TRUE, BFD_RELOC_BEXKAT1_15_PCREL); break; case BEXKAT1_LOAD: case BEXKAT1_STORE: // A, regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A if (*op_end != ',') { as_bad(_("missing comma: %s"), op_end); return; } op_end++; while (ISSPACE(*op_end)) op_end++; /* __attribute__((fallthrough)); */ case BEXKAT1_JUMP: if (opcode->size) { // big address md_number_to_chars(p, iword, 4); op_end = parse_exp_save_ilp(op_end, &arg); p = frag_more(4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } else { // exp(B) if (*op_end != '(') op_end = parse_exp_save_ilp(op_end, &arg); else { // Implicit 0 offset to allow for indirect arg.X_op = O_constant; arg.X_add_number = 0; } if (*op_end != '(') { as_bad(_("missing open paren: %s"), op_end); ignore_rest_of_line(); return; } op_end++; // burn paren while (ISSPACE(*op_end)) op_end++; regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 16; // B if (*op_end != ')') { as_bad(_("missing close paren: %s"), op_end); ignore_rest_of_line(); return; } op_end++; if (arg.X_op != O_constant) { as_bad(_("offset is not a constant expression")); ignore_rest_of_line(); return; } offset = arg.X_add_number; if (offset < -16384 || offset > 16383) { as_bad(_("offset is out of range: %d\n"), offset); ignore_rest_of_line(); return; } md_number_to_chars(p, iword, 4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_BEXKAT1_15); } break; case BEXKAT1_LDI: regnum = parse_regnum(&op_end); if (regnum == -1) return; while (ISSPACE(*op_end)) op_end++; iword |= (regnum & 0xf) << 20; // A if (*op_end != ',') { as_bad(_("missing comma: %s"), op_end); return; } op_end++; while (ISSPACE(*op_end)) op_end++; op_end = parse_exp_save_ilp(op_end, &arg); if (opcode->size) { md_number_to_chars(p, iword, 4); p = frag_more(4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_32); } else { if (arg.X_op != O_constant) { as_bad(_("offset is not a constant expression")); ignore_rest_of_line(); return; } offset = arg.X_add_number; if (offset >= 32768) { as_bad(_("offset is out of range: %d\n"), offset); ignore_rest_of_line(); return; } md_number_to_chars(p, iword, 4); fix_new_exp(frag_now, (p - frag_now->fr_literal), 4, &arg, 0, BFD_RELOC_BEXKAT1_15); } break; } while (ISSPACE(*op_end)) op_end++; if (*op_end != 0) as_warn("extra stuff on line ignored %s %c", op_start, *op_end); if (pending_reloc) as_bad("Something forgot to clean up\n"); return; }
case O_R32: return BFD_RELOC_PJ_CODE_REL32; case O_32: return BFD_RELOC_PJ_CODE_DIR32; } abort (); return 0; } /* Handler for the ipush fake opcode, turns ipush <foo> into sipush lo16<foo>, sethi hi16<foo>. */ static void ipush_code (pj_opc_info_t *opcode ATTRIBUTE_UNUSED, char *str) { char *b = frag_more (6); expressionS arg; b[0] = 0x11; b[3] = 0xed; parse_exp_save_ilp (str + 1, &arg); if (pending_reloc) { as_bad (_("can't have relocation for ipush")); pending_reloc = 0; } fix_new_exp (frag_now, b - frag_now->fr_literal + 1, 2, &arg, 0, BFD_RELOC_PJ_CODE_DIR16); fix_new_exp (frag_now, b - frag_now->fr_literal + 4, 2, &arg, 0, BFD_RELOC_PJ_CODE_HI16);
static void output_cfi_insn (struct cfi_insn_data *insn) { offsetT offset; unsigned int regno; switch (insn->insn) { case DW_CFA_advance_loc: { symbolS *from = insn->u.ll.lab1; symbolS *to = insn->u.ll.lab2; if (symbol_get_frag (to) == symbol_get_frag (from)) { addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; if (scaled <= 0x3F) out_one (DW_CFA_advance_loc + scaled); else if (scaled <= 0xFF) { out_one (DW_CFA_advance_loc1); out_one (scaled); } else if (scaled <= 0xFFFF) { out_one (DW_CFA_advance_loc2); out_two (scaled); } else { out_one (DW_CFA_advance_loc4); out_four (scaled); } } else { expressionS exp; exp.X_op = O_subtract; exp.X_add_symbol = to; exp.X_op_symbol = from; exp.X_add_number = 0; /* The code in ehopt.c expects that one byte of the encoding is already allocated to the frag. This comes from the way that it scans the .eh_frame section looking first for the .byte DW_CFA_advance_loc4. */ *frag_more (1) = DW_CFA_advance_loc4; frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3, make_expr_symbol (&exp), frag_now_fix () - 1, (char *) frag_now); } } break; case DW_CFA_def_cfa: offset = insn->u.ri.offset; if (offset < 0) { out_one (DW_CFA_def_cfa_sf); out_uleb128 (insn->u.ri.reg); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa); out_uleb128 (insn->u.ri.reg); out_uleb128 (offset); } break; case DW_CFA_def_cfa_register: case DW_CFA_undefined: case DW_CFA_same_value: out_one (insn->insn); out_uleb128 (insn->u.r); break; case DW_CFA_def_cfa_offset: offset = insn->u.i; if (offset < 0) { out_one (DW_CFA_def_cfa_offset_sf); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa_offset); out_uleb128 (offset); } break; case DW_CFA_restore: regno = insn->u.r; if (regno <= 0x3F) { out_one (DW_CFA_restore + regno); } else { out_one (DW_CFA_restore_extended); out_uleb128 (regno); } break; case DW_CFA_offset: regno = insn->u.ri.reg; offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; if (offset < 0) { out_one (DW_CFA_offset_extended_sf); out_uleb128 (regno); out_sleb128 (offset); } else if (regno <= 0x3F) { out_one (DW_CFA_offset + regno); out_uleb128 (offset); } else { out_one (DW_CFA_offset_extended); out_uleb128 (regno); out_uleb128 (offset); } break; case DW_CFA_register: out_one (DW_CFA_register); out_uleb128 (insn->u.rr.reg1); out_uleb128 (insn->u.rr.reg2); break; case DW_CFA_remember_state: case DW_CFA_restore_state: out_one (insn->insn); break; case DW_CFA_GNU_window_save: out_one (DW_CFA_GNU_window_save); break; case CFI_escape: { struct cfi_escape_data *e; for (e = insn->u.esc; e ; e = e->next) emit_expr (&e->exp, 1); break; } case CFI_val_encoded_addr: { unsigned encoding = insn->u.ea.encoding; offsetT encoding_size; if (encoding == DW_EH_PE_omit) break; out_one (DW_CFA_val_expression); out_uleb128 (insn->u.ea.reg); switch (encoding & 0x7) { case DW_EH_PE_absptr: encoding_size = DWARF2_ADDR_SIZE (stdoutput); break; case DW_EH_PE_udata2: encoding_size = 2; break; case DW_EH_PE_udata4: encoding_size = 4; break; case DW_EH_PE_udata8: encoding_size = 8; break; default: abort (); } /* If the user has requested absolute encoding, then use the smaller DW_OP_addr encoding. */ if (insn->u.ea.encoding == DW_EH_PE_absptr) { out_uleb128 (1 + encoding_size); out_one (DW_OP_addr); } else { out_uleb128 (1 + 1 + encoding_size); out_one (DW_OP_GNU_encoded_addr); out_one (encoding); if ((encoding & 0x70) == DW_EH_PE_pcrel) { #if CFI_DIFF_EXPR_OK insn->u.ea.exp.X_op = O_subtract; insn->u.ea.exp.X_op_symbol = symbol_temp_new_now (); #elif defined (tc_cfi_emit_pcrel_expr) tc_cfi_emit_pcrel_expr (&insn->u.ea.exp, encoding_size); break; #else abort (); #endif } } emit_expr (&insn->u.ea.exp, encoding_size); } break; default: abort (); } }
static void out_sleb128 (offsetT value) { output_leb128 (frag_more (sizeof_leb128 (value, 1)), value, 1); }
static void output_cfi_insn (struct cfi_insn_data *insn) { offsetT offset; unsigned int regno; switch (insn->insn) { case DW_CFA_advance_loc: { symbolS *from = insn->u.ll.lab1; symbolS *to = insn->u.ll.lab2; if (symbol_get_frag (to) == symbol_get_frag (from)) { addressT delta = S_GET_VALUE (to) - S_GET_VALUE (from); addressT scaled = delta / DWARF2_LINE_MIN_INSN_LENGTH; if (scaled <= 0x3F) out_one (DW_CFA_advance_loc + scaled); else if (delta <= 0xFF) { out_one (DW_CFA_advance_loc1); out_one (delta); } else if (delta <= 0xFFFF) { out_one (DW_CFA_advance_loc2); out_two (delta); } else { out_one (DW_CFA_advance_loc4); out_four (delta); } } else { expressionS exp; exp.X_op = O_subtract; exp.X_add_symbol = to; exp.X_op_symbol = from; exp.X_add_number = 0; /* The code in ehopt.c expects that one byte of the encoding is already allocated to the frag. This comes from the way that it scans the .eh_frame section looking first for the .byte DW_CFA_advance_loc4. */ frag_more (1); frag_var (rs_cfa, 4, 0, DWARF2_LINE_MIN_INSN_LENGTH << 3, make_expr_symbol (&exp), frag_now_fix () - 1, (char *) frag_now); } } break; case DW_CFA_def_cfa: offset = insn->u.ri.offset; if (offset < 0) { out_one (DW_CFA_def_cfa_sf); out_uleb128 (insn->u.ri.reg); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa); out_uleb128 (insn->u.ri.reg); out_uleb128 (offset); } break; case DW_CFA_def_cfa_register: case DW_CFA_undefined: case DW_CFA_same_value: out_one (insn->insn); out_uleb128 (insn->u.r); break; case DW_CFA_def_cfa_offset: offset = insn->u.i; if (offset < 0) { out_one (DW_CFA_def_cfa_offset_sf); out_sleb128 (offset / DWARF2_CIE_DATA_ALIGNMENT); } else { out_one (DW_CFA_def_cfa_offset); out_uleb128 (offset); } break; case DW_CFA_restore: regno = insn->u.r; if (regno <= 0x3F) { out_one (DW_CFA_restore + regno); } else { out_one (DW_CFA_restore_extended); out_uleb128 (regno); } break; case DW_CFA_offset: regno = insn->u.ri.reg; offset = insn->u.ri.offset / DWARF2_CIE_DATA_ALIGNMENT; if (offset < 0) { out_one (DW_CFA_offset_extended_sf); out_uleb128 (regno); out_sleb128 (offset); } else if (regno <= 0x3F) { out_one (DW_CFA_offset + regno); out_uleb128 (offset); } else { out_one (DW_CFA_offset_extended); out_uleb128 (regno); out_uleb128 (offset); } break; case DW_CFA_register: out_one (DW_CFA_register); out_uleb128 (insn->u.rr.reg1); out_uleb128 (insn->u.rr.reg2); break; case DW_CFA_remember_state: case DW_CFA_restore_state: out_one (insn->insn); break; case DW_CFA_GNU_window_save: out_one (DW_CFA_GNU_window_save); break; case CFI_escape: { struct cfi_escape_data *e; for (e = insn->u.esc; e ; e = e->next) emit_expr (&e->exp, 1); break; } default: abort (); } }