symbolS * expr_build_uconstant (offsetT value) { expressionS e; e.X_op = O_constant; e.X_add_number = value; e.X_unsigned = 1; return make_expr_symbol (&e); }
static symbolS * expr_build_binary (operatorT op, symbolS * s1, symbolS * s2) { expressionS e; e.X_op = op; e.X_add_symbol = s1; e.X_op_symbol = s2; e.X_add_number = 0; return make_expr_symbol (& e); }
static void relax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym) { expressionS expr; int max_chars; expr.X_op = O_subtract; expr.X_add_symbol = to_sym; expr.X_op_symbol = from_sym; expr.X_add_number = 0; /* The maximum size of the frag is the line delta with a maximum sized address delta. */ max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH); frag_var (rs_dwarf2dbg, max_chars, max_chars, 1, make_expr_symbol (&expr), line_delta, NULL); }
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 (); } }
int check_eh_frame (expressionS *exp, unsigned int *pnbytes) { struct frame_data { enum frame_state state; int cie_info_ok; struct cie_info cie_info; symbolS *size_end_sym; fragS *loc4_frag; int loc4_fix; int aug_size; int aug_shift; }; static struct frame_data eh_frame_data; static struct frame_data debug_frame_data; struct frame_data *d; /* Don't optimize. */ if (flag_traditional_format) return 0; #ifdef md_allow_eh_opt if (! md_allow_eh_opt) return 0; #endif /* Select the proper section data. */ if (strncmp (segment_name (now_seg), ".eh_frame", 9) == 0 && segment_name (now_seg)[9] != '_') d = &eh_frame_data; else if (strncmp (segment_name (now_seg), ".debug_frame", 12) == 0) d = &debug_frame_data; else return 0; if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym)) { /* We have come to the end of the CIE or FDE. See below where we set saw_size. We must check this first because we may now be looking at the next size. */ d->state = state_idle; } switch (d->state) { case state_idle: if (*pnbytes == 4) { /* This might be the size of the CIE or FDE. We want to know the size so that we don't accidentally optimize across an FDE boundary. We recognize the size in one of two forms: a symbol which will later be defined as a difference, or a subtraction of two symbols. Either way, we can tell when we are at the end of the FDE because the symbol becomes defined (in the case of a subtraction, the end symbol, from which the start symbol is being subtracted). Other ways of describing the size will not be optimized. */ if ((exp->X_op == O_symbol || exp->X_op == O_subtract) && ! S_IS_DEFINED (exp->X_add_symbol)) { d->state = state_saw_size; d->size_end_sym = exp->X_add_symbol; } } break; case state_saw_size: case state_saw_cie_offset: /* Assume whatever form it appears in, it appears atomically. */ d->state = (enum frame_state) (d->state + 1); break; case state_saw_pc_begin: /* Decide whether we should see an augmentation. */ if (! d->cie_info_ok && ! (d->cie_info_ok = get_cie_info (&d->cie_info))) d->state = state_error; else if (d->cie_info.z_augmentation) { d->state = state_seeing_aug_size; d->aug_size = 0; d->aug_shift = 0; } else d->state = state_wait_loc4; break; case state_seeing_aug_size: /* Bytes == -1 means this comes from an leb128 directive. */ if ((int)*pnbytes == -1 && exp->X_op == O_constant) { d->aug_size = exp->X_add_number; d->state = state_skipping_aug; } else if (*pnbytes == 1 && exp->X_op == O_constant) { unsigned char byte = exp->X_add_number; d->aug_size |= (byte & 0x7f) << d->aug_shift; d->aug_shift += 7; if ((byte & 0x80) == 0) d->state = state_skipping_aug; } else d->state = state_error; if (d->state == state_skipping_aug && d->aug_size == 0) d->state = state_wait_loc4; break; case state_skipping_aug: if ((int)*pnbytes < 0) d->state = state_error; else { int left = (d->aug_size -= *pnbytes); if (left == 0) d->state = state_wait_loc4; else if (left < 0) d->state = state_error; } break; case state_wait_loc4: if (*pnbytes == 1 && exp->X_op == O_constant && exp->X_add_number == DW_CFA_advance_loc4) { /* This might be a DW_CFA_advance_loc4. Record the frag and the position within the frag, so that we can change it later. */ frag_grow (1); d->state = state_saw_loc4; d->loc4_frag = frag_now; d->loc4_fix = frag_now_fix (); } break; case state_saw_loc4: d->state = state_wait_loc4; if (*pnbytes != 4) break; if (exp->X_op == O_constant) { /* This is a case which we can optimize. The two symbols being subtracted were in the same frag and the expression was reduced to a constant. We can do the optimization entirely in this function. */ if (exp->X_add_number < 0x40) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc | exp->X_add_number; /* No more bytes needed. */ return 1; } else if (exp->X_add_number < 0x100) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; *pnbytes = 1; } else if (exp->X_add_number < 0x10000) { d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; *pnbytes = 2; } } else if (exp->X_op == O_subtract && d->cie_info.code_alignment == 1) { /* This is a case we can optimize. The expression was not reduced, so we can not finish the optimization until the end of the assembly. We set up a variant frag which we handle later. */ frag_var (rs_cfa, 4, 0, 1 << 3, make_expr_symbol (exp), d->loc4_fix, (char *) d->loc4_frag); return 1; } else if ((exp->X_op == O_divide || exp->X_op == O_right_shift) && d->cie_info.code_alignment > 1) { if (symbol_symbolS (exp->X_add_symbol) && symbol_constant_p (exp->X_op_symbol) && S_GET_SEGMENT (exp->X_op_symbol) == absolute_section && ((exp->X_op == O_divide ? *symbol_X_add_number (exp->X_op_symbol) : (offsetT) 1 << *symbol_X_add_number (exp->X_op_symbol)) == (offsetT) d->cie_info.code_alignment)) { expressionS *symval; symval = symbol_get_value_expression (exp->X_add_symbol); if (symval->X_op == O_subtract) { /* This is a case we can optimize as well. The expression was not reduced, so we can not finish the optimization until the end of the assembly. We set up a variant frag which we handle later. */ frag_var (rs_cfa, 4, 0, d->cie_info.code_alignment << 3, make_expr_symbol (symval), d->loc4_fix, (char *) d->loc4_frag); return 1; } } } break; case state_error: /* Just skipping everything. */ break; } return 0; }
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 (); } }
const char * gas_cgen_parse_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, enum cgen_parse_operand_type want, const char **strP, int opindex, int opinfo, enum cgen_parse_operand_result *resultP, bfd_vma *valueP) { #ifdef __STDC__ /* These are volatile to survive the setjmp. */ char * volatile hold; enum cgen_parse_operand_result * volatile resultP_1; volatile int opinfo_1; #else static char *hold; static enum cgen_parse_operand_result *resultP_1; int opinfo_1; #endif const char *errmsg; expressionS exp; #ifdef OBJ_COMPLEX_RELC volatile int signed_p = 0; symbolS * stmp = NULL; bfd_reloc_code_real_type reloc_type; const CGEN_OPERAND * operand; fixS dummy_fixup; #endif if (want == CGEN_PARSE_OPERAND_INIT) { gas_cgen_init_parse (); return NULL; } resultP_1 = resultP; hold = input_line_pointer; input_line_pointer = (char *) *strP; opinfo_1 = opinfo; /* We rely on md_operand to longjmp back to us. This is done via gas_cgen_md_operand. */ if (setjmp (expr_jmp_buf) != 0) { expr_jmp_buf_p = 0; input_line_pointer = (char *) hold; *resultP_1 = CGEN_PARSE_OPERAND_RESULT_ERROR; return _("illegal operand"); } expr_jmp_buf_p = 1; expression (&exp); expr_jmp_buf_p = 0; errmsg = NULL; *strP = input_line_pointer; input_line_pointer = hold; #ifdef TC_CGEN_PARSE_FIX_EXP opinfo_1 = TC_CGEN_PARSE_FIX_EXP (opinfo_1, & exp); #endif /* FIXME: Need to check `want'. */ switch (exp.X_op) { case O_illegal: errmsg = _("illegal operand"); *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_absent: errmsg = _("missing operand"); *resultP = CGEN_PARSE_OPERAND_RESULT_ERROR; break; case O_constant: if (want == CGEN_PARSE_OPERAND_SYMBOLIC) goto de_fault; *valueP = exp.X_add_number; *resultP = CGEN_PARSE_OPERAND_RESULT_NUMBER; break; case O_register: *valueP = exp.X_add_number; *resultP = CGEN_PARSE_OPERAND_RESULT_REGISTER; break; de_fault: default: #ifdef OBJ_COMPLEX_RELC /* Look up operand, check to see if there's an obvious overflow (this helps disambiguate some insn parses). */ operand = cgen_operand_lookup_by_num (cd, opindex); errmsg = weak_operand_overflow_check (& exp, operand); if (! errmsg) { /* Fragment the expression as necessary, and queue a reloc. */ memset (& dummy_fixup, 0, sizeof (fixS)); reloc_type = md_cgen_lookup_reloc (0, operand, & dummy_fixup); if (exp.X_op == O_symbol && reloc_type == BFD_RELOC_RELC && exp.X_add_symbol->sy_value.X_op == O_constant && (!exp.X_add_symbol->bsym || (exp.X_add_symbol->bsym->section != expr_section && exp.X_add_symbol->bsym->section != absolute_section && exp.X_add_symbol->bsym->section != undefined_section))) { /* Local labels will have been (eagerly) turned into constants by now, due to the inappropriately deep insight of the expression parser. Unfortunately make_expr_symbol prematurely dives into the symbol evaluator, and in this case it gets a bad answer, so we manually create the expression symbol we want here. */ stmp = symbol_create (FAKE_LABEL_NAME, expr_section, 0, & zero_address_frag); symbol_set_value_expression (stmp, & exp); } else stmp = make_expr_symbol (& exp); /* If this is a pc-relative RELC operand, we need to subtract "." from the expression. */ if (reloc_type == BFD_RELOC_RELC && CGEN_OPERAND_ATTR_VALUE (operand, CGEN_OPERAND_PCREL_ADDR)) stmp = expr_build_binary (O_subtract, stmp, expr_build_dot ()); /* FIXME: this is not a perfect heuristic for figuring out whether an operand is signed: it only works when the operand is an immediate. it's not terribly likely that any other values will be signed relocs, but it's possible. */ if (operand && (operand->hw_type == HW_H_SINT)) signed_p = 1; if (stmp->bsym && (stmp->bsym->section == expr_section) && ! S_IS_LOCAL (stmp)) { if (signed_p) stmp->bsym->flags |= BSF_SRELC; else stmp->bsym->flags |= BSF_RELC; } /* Now package it all up for the fixup emitter. */ exp.X_op = O_symbol; exp.X_op_symbol = 0; exp.X_add_symbol = stmp; exp.X_add_number = 0; /* Re-init rightshift quantity, just in case. */ rightshift = operand->length; queue_fixup_recursively (opindex, opinfo_1, & exp, (reloc_type == BFD_RELOC_RELC) ? & (operand->index_fields) : 0, signed_p, -1); } * resultP = errmsg ? CGEN_PARSE_OPERAND_RESULT_ERROR : CGEN_PARSE_OPERAND_RESULT_QUEUED; *valueP = 0; #else queue_fixup (opindex, opinfo_1, &exp); *valueP = 0; *resultP = CGEN_PARSE_OPERAND_RESULT_QUEUED; #endif break; } return errmsg; }