Index: config/tc-mips.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-mips.c,v retrieving revision 1.536 diff -p -u -r1.536 tc-mips.c --- config/tc-mips.c 31 May 2013 17:04:52 -0000 1.536 +++ config/tc-mips.c 31 May 2013 17:24:20 -0000 @@ -15712,7 +15712,8 @@ md_apply_fix (fixS *fixP, valueT *valP, || fixP->fx_r_type == BFD_RELOC_MICROMIPS_SUB || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64); + || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64 + || fixP->fx_r_type == BFD_RELOC_NONE); buf = fixP->fx_frag->fr_literal + fixP->fx_where; @@ -15951,6 +15952,7 @@ md_apply_fix (fixS *fixP, valueT *valP, S_SET_WEAK (fixP->fx_addsy); break; + case BFD_RELOC_NONE: case BFD_RELOC_VTABLE_ENTRY: fixP->fx_done = 0; break; @@ -19793,3 +19795,289 @@ tc_mips_regname_to_dw2regnum (char *regn return regnum; } + +#if defined (OBJ_ELF) +segT +mips_make_debug_seg (segT cseg, char *name) +{ + const char *group_name = NULL; + int linkonce; + int flags = 0; + + if (cseg && (cseg->flags & SEC_LINK_ONCE) != 0) + { + group_name = elf_group_name (cseg); + if (group_name == NULL) + { + as_bad (_("Group section `%s' has no group signature"), + segment_name (cseg)); + } + flags |= SHF_GROUP; + linkonce = 1; + } + obj_elf_change_section (name, SHT_PROGBITS, flags, 0, group_name, linkonce, 0); + return now_seg; +} + +/* TODO: Can also save float regs. */ +#define MIPS_NUM_UNWIND_REGS 32 + +static int +mips_unwind_reg_from_dwarf (int reg) +{ + if (reg > MIPS_NUM_UNWIND_REGS) + return -1; + + return reg; +} + +/* Attempt to generate compact frame unwind encodings. */ + +void +mips_cfi_endproc (struct fde_entry *fde ATTRIBUTE_UNUSED) +{ + struct cfi_insn_data *insn; + int reg; + offsetT cfa_offset = 0; + offsetT next_offset = 0; + bfd_boolean reg_offset[MIPS_NUM_UNWIND_REGS]; + int cfa_reg = 29; + bfd_byte opbuff[40]; + int num_ops; + int i; + bfd_byte op; + offsetT stack_align = HAVE_NEWABI ? 16 : 8; + offsetT gpr_size = HAVE_64BIT_GPRS ? 8 : 4; + + for (reg = 0; reg < MIPS_NUM_UNWIND_REGS; reg++) + reg_offset[reg] = 0; + + /* Scan FDE instructions to build up stack frame layout. */ + for (insn = fde->data; insn; insn = insn->next) + { + switch (insn->insn) + { + case DW_CFA_advance_loc: + break; + + case DW_CFA_def_cfa: + cfa_reg = insn->u.ri.reg; + cfa_offset = insn->u.ri.offset; + break; + + case DW_CFA_def_cfa_register: + cfa_reg = insn->u.r; + break; + + case DW_CFA_def_cfa_offset: + cfa_offset = insn->u.i; + break; + + case DW_CFA_undefined: + case DW_CFA_same_value: + reg = mips_unwind_reg_from_dwarf (insn->u.r); + if (reg >= 0) + reg_offset[reg] = 0; + break; + + case DW_CFA_offset: + reg = mips_unwind_reg_from_dwarf (insn->u.ri.reg); + if (reg < 0) + return; + if (insn->u.ri.offset >= 0) + return; + reg_offset[reg] = insn->u.ri.offset; + break; + + default: + abort (); + } + } + + /* Frame pointer must be callee caved. */ + if (cfa_reg < 16 + || (cfa_reg > 23 && cfa_reg < 29) + || cfa_reg > 30) + return; + + /* Can only increment stack pointer. */ + if (cfa_offset < 0) + return; + + /* Stack must be aligned. */ + if ((cfa_offset & (stack_align - 1)) != 0) + return; + + /* Registers must be contiguous. There's only limited benefit in + supprting more complex layouts, so For now we also require they + be in order. */ + next_offset = -gpr_size; + for (i = MIPS_NUM_UNWIND_REGS - 1; i >= 0; i--) + { + if (reg_offset[i] == 0) + continue; + + if (reg_offset[i] != next_offset) + return; + + next_offset -= gpr_size; + } + + num_ops = 0; + if (cfa_reg != 29) + opbuff[num_ops++] = 0x50 + cfa_reg - 16; + + cfa_offset /= stack_align; + if (cfa_offset && cfa_offset <= 129) + { + while (cfa_offset > 64) + { + opbuff[num_ops++] = 0x3f; + cfa_offset -= 64; + } + opbuff[num_ops++] = cfa_offset - 1; + } + else if (cfa_offset > 0) + { + opbuff[num_ops++] = 0x58; + cfa_offset -= 129; + while (cfa_offset > 0x7f) + { + opbuff[num_ops++] = (cfa_offset & 0x7f) | 0x80; + cfa_offset >>= 7; + } + opbuff[num_ops++] = cfa_offset; + } + + op = 0; + /* r16[-r23], [r30], r31 */ + if (reg_offset[31]) + { + if (reg_offset[30]) + op = 0x48; + else + op = 0x40; + + for (i = 29; i > 23; i--) + { + if (reg_offset[i]) + op = 0; + } + + while (i > 16 && reg_offset[i] == 0) + i--; + + reg = i; + for (i = 16; i <= reg; i++) + if (reg_offset[i] == 0) + op = 0; + + if (op) + op |= (reg - 16); + } + + if (!op) + { + /* mips16 save multiple. */ + op = 0x6c; + if (reg_offset[16] == 0 || reg_offset[17] == 0 + || reg_offset[21] == 0 || reg_offset[22] == 0 + || reg_offset[23] == 0 || reg_offset[31] == 0) + op = 0; + + for (i = 24; i < 31; i++) + if (reg_offset[i] != 0) + op = 0; + + if (op && reg_offset[18] == 0) + op++; + if (reg_offset[19] == 0) + { + if (op == 0x6d) + op++; + else + op = 0; + } + if (reg_offset[20] == 0) + { + if (op == 0x6e) + op++; + else + op = 0; + } + } + + if (op) + { + opbuff[num_ops++] = op; + reg = 15; + } + else + { + reg = 31; + } + /* Arbitrary blocks of registers. */ + i = 0; + while (reg >= 0) + { + if (reg_offset[reg] == 0) + { + if (i) + { + opbuff[num_ops++] = 0x59; + opbuff[num_ops++] = ((reg + 1) << 3) | (i - 1); + i = 0; + } + } + else + i++; + reg--; + } + + if (i) + { + opbuff[num_ops++] = 0x59; + opbuff[num_ops++] = i - 1; + } + + if (fde->lsda_encoding != DW_EH_PE_omit) + fde->eh_header_type = EH_COMPACT_HAS_LSDA; + else if (num_ops <= 3 && fde->per_encoding == DW_EH_PE_omit) + fde->eh_header_type = EH_COMPACT_INLINE; + else + fde->eh_header_type = EH_COMPACT_OUTLINE; + + if (fde->eh_header_type == EH_COMPACT_INLINE) + { + while (num_ops < 3) + opbuff[num_ops++] = 0x5c; + } + + fde->eh_data_size = num_ops; + fde->eh_data = (bfd_byte *) xmalloc (num_ops); + memcpy (fde->eh_data, opbuff, num_ops); +} + +void +mips_cfi_fix_eh_ref (char *where, expressionS *exp) +{ + fix_new (frag_now, where - frag_now->fr_literal, 4, exp->X_add_symbol, + exp->X_add_number, FALSE, BFD_RELOC_MIPS_EH); +} + +void +mips_cfi_emit_expr (expressionS *exp, int encoding) +{ + char *p; + + p = frag_more(4); + md_number_to_chars (p, 0, 4); + if ((encoding & 0x70) == DW_EH_PE_datarel) + mips_cfi_fix_eh_ref (p, exp); + else + { + fix_new (frag_now, p - frag_now->fr_literal, 4, exp->X_add_symbol, + exp->X_add_number, TRUE, BFD_RELOC_32_PCREL); + } +} +#endif Index: config/tc-mips.h =================================================================== RCS file: /cvs/src/src/gas/config/tc-mips.h,v retrieving revision 1.59 diff -p -u -r1.59 tc-mips.h --- config/tc-mips.h 23 Sep 2012 11:14:25 -0000 1.59 +++ config/tc-mips.h 31 May 2013 17:24:20 -0000 @@ -177,7 +177,9 @@ extern enum dwarf2_format mips_dwarf2_fo extern int mips_dwarf2_addr_size (void); #define DWARF2_ADDR_SIZE(bfd) mips_dwarf2_addr_size () -#define DWARF2_FDE_RELOC_SIZE mips_dwarf2_addr_size () +#define DWARF2_FDE_RELOC_SIZE (compact_eh ? 4 : mips_dwarf2_addr_size ()) +#define DWARF2_FDE_RELOC_ENCODING(enc) \ + (enc | (compact_eh ? DW_EH_PE_pcrel : 0)) #define TARGET_USE_CFIPOP 1 @@ -190,4 +192,24 @@ extern int tc_mips_regname_to_dw2regnum #define DWARF2_DEFAULT_RETURN_COLUMN 31 #define DWARF2_CIE_DATA_ALIGNMENT (-4) +#if defined (OBJ_ELF) + +#define tc_make_debug_seg mips_make_debug_seg +segT mips_make_debug_seg (segT cseg, char *name); + +#define tc_cfi_endproc mips_cfi_endproc +struct fde_entry; +void mips_cfi_endproc (struct fde_entry *fde); + +#define tc_cfi_emit_expr mips_cfi_emit_expr +void mips_cfi_emit_expr (expressionS *exp, int encoding); +#define tc_cfi_special_encoding(e) \ + ((e) == (DW_EH_PE_sdata4 | DW_EH_PE_datarel | DW_EH_PE_indirect) \ + || (e) == (DW_EH_PE_sdata4 | DW_EH_PE_pcrel)) + +#define tc_cfi_fix_eh_ref mips_cfi_fix_eh_ref +void mips_cfi_fix_eh_ref (char *where, expressionS *exp); + +#endif /* OBJ_ELF */ + #endif /* TC_MIPS */