void dwarf2_move_insn (int delta) { struct line_subseg *lss; struct line_entry *e; valueT now; if (delta == 0) return; lss = get_line_subseg (now_seg, now_subseg, FALSE); if (!lss) return; now = frag_now_fix (); while ((e = *lss->pmove_tail)) { if (S_GET_VALUE (e->label) == now) S_SET_VALUE (e->label, now + delta); lss->pmove_tail = &e->next; } }
static void dot_cfi_escape (int ignored ATTRIBUTE_UNUSED) { struct cfi_escape_data *head, **tail, *e; struct cfi_insn_data *insn; if (frchain_now->frch_cfi_data == NULL) { as_bad (_("CFI instruction used without previous .cfi_startproc")); ignore_rest_of_line (); return; } /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) != frag_now_fix ()) cfi_add_advance_loc (symbol_temp_new_now ()); tail = &head; do { e = xmalloc (sizeof (*e)); do_parse_cons_expression (&e->exp, 1); *tail = e; tail = &e->next; } while (*input_line_pointer++ == ','); *tail = NULL; insn = alloc_cfi_insn_data (); insn->insn = CFI_escape; insn->u.esc = head; --input_line_pointer; demand_empty_rest_of_line (); }
/* * layout_addresses() is called after all the assembly code has been read and * fragments, symbols and fixups have been created. This routine sets the * address of the fragments and symbols. Then it does the fixups of the frags * and prepares the fixes so relocation entries can be created from them. */ void layout_addresses( void) { struct frchain *frchainP; fragS *fragP; relax_addressT slide, tmp; symbolS *symbolP; uint32_t nbytes, fill_size, repeat_expression, partial_bytes, layout_pass; relax_stateT old_fr_type; int changed; if(frchain_root == NULL) return; /* * If there is any current frag close it off. */ if(frag_now != NULL && frag_now->fr_fix == 0){ frag_now->fr_fix = obstack_next_free(&frags) - frag_now->fr_literal; frag_wane(frag_now); } /* * For every section, add a last ".fill 0" frag that will later be used * as the ending address of that section. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ /* * We must do the obstack_finish(), so the next object we put on * obstack frags will not appear to start at the fr_literal of the * current frag. Also, it ensures that the next object will begin * on a address that is aligned correctly for the engine that runs * the assembler. */ (void)obstack_finish(&frags); /* * Make a fresh frag for the last frag. */ frag_now = (fragS *)obstack_alloc(&frags, SIZEOF_STRUCT_FRAG); memset(frag_now, '\0', SIZEOF_STRUCT_FRAG); frag_now->fr_next = NULL; (void)obstack_finish(&frags); /* * Append the new frag to current frchain. */ frchainP->frch_last->fr_next = frag_now; frchainP->frch_last = frag_now; frag_wane(frag_now); } /* * Now set the relative addresses of frags within the section by * relaxing each section. That is all sections will start at address * zero and addresses of the frags in that section will increase from * there. * * The debug sections are done last as other section are needed to be * done first becase debug sections may have line numbers with .loc * directives in them and their sizes need to be set before processing * the line number sections. We also do sections that have rs_leb128s * in them before debug sections but after other sections since they * are used for things like exception tables and they may be refering to * sections such that their sizes too must be known first. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & S_ATTR_DEBUG) == S_ATTR_DEBUG) frchainP->layout_pass = 2; else if(frchainP->has_rs_leb128s == TRUE) frchainP->layout_pass = 1; else frchainP->layout_pass = 0; } for(layout_pass = 0; layout_pass < 3; layout_pass++){ do{ changed = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if(frchainP->layout_pass != layout_pass) continue; if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL) continue; /* * This is done so in case md_estimate_size_before_relax() * (called by relax_section) wants to make fixSs they are * for this section. */ frchain_now = frchainP; changed += relax_section(frchainP->frch_root, frchainP->frch_nsect); } } while(changed != 0); } /* * Now set the absolute addresses of all frags by sliding the frags in * each non-zerofill section by the address ranges taken up by the * sections before it. */ slide = 0; for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) == S_ZEROFILL) continue; slide = round(slide, 1 << frchainP->frch_section.align); tmp = frchainP->frch_last->fr_address; if(slide != 0){ for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){ fragP->fr_address += slide; } } slide += tmp; } /* * Now with the non-zerofill section addresses set set all of the * addresses of the zerofill sections. Comming in the fr_address is * the size of the section and going out it is the start address. This * will make layout_symbols() work out naturally. The only funky thing * is that section numbers do not end up in address order. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ if((frchainP->frch_section.flags & SECTION_TYPE) != S_ZEROFILL) continue; slide = round(slide, 1 << frchainP->frch_section.align); tmp = frchainP->frch_root->fr_address; frchainP->frch_root->fr_address = slide; frchainP->frch_last->fr_address = tmp + slide; slide += tmp; } /* * Set the symbol addresses based on their frag's address. * First forward references are handled. */ for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ if(symbolP->sy_forward != NULL){ if(symbolP->sy_nlist.n_type & N_STAB) symbolP->sy_other = symbolP->sy_forward->sy_other; symbolP->sy_value += symbolP->sy_forward->sy_value + symbolP->sy_forward->sy_frag->fr_address; symbolP->sy_forward = 0; } } for(symbolP = symbol_rootP; symbolP; symbolP = symbolP->sy_next){ symbolP->sy_value += symbolP->sy_frag->fr_address; } /* * At this point the addresses of frags now reflect addresses we use in * the object file and the symbol values are correct. * Scan the frags, converting any ".org"s and ".align"s to ".fill"s. * Also converting any machine-dependent frags using md_convert_frag(); */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ /* * This is done so any fixes created by md_convert_frag() are for * this section. */ frchain_now = frchainP; for(fragP = frchainP->frch_root; fragP; fragP = fragP->fr_next){ switch(fragP->fr_type){ case rs_align: case rs_org: old_fr_type = fragP->fr_type; /* convert this frag to an rs_fill type */ fragP->fr_type = rs_fill; /* * Calculate the number of bytes the variable part of the * the rs_fill frag will need to fill. Then calculate this * as the fill_size * repeat_expression + partial_bytes. */ know(fragP->fr_next != NULL); nbytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix; if(nbytes < 0){ as_warn("rs_org invalid, dot past value by %d bytes", nbytes); nbytes = 0; } fill_size = fragP->fr_var; repeat_expression = nbytes / fill_size; #ifdef I386 /* * For x86 architecures in sections containing only * instuctions being padded with nops that are aligned to 16 * bytes or less and are assembled with -dynamic we will * actually end up padding with the optimal nop sequence. * Previously there has been the maximum number of bytes * allocated in the frag to use for this. */ if(old_fr_type == rs_align && (frchain_now->frch_section.flags & S_ATTR_PURE_INSTRUCTIONS) != 0 && fill_size == 1 && fragP->fr_literal[fragP->fr_fix] == (char)0x90 && nbytes > 0 && nbytes < 16 && flagseen['k'] == TRUE){ i386_align_code(fragP, nbytes); /* * The call to i386_align_code() has set the fill_size * in fragP->fr_var to nbytes. So we set the fr_offset * to the fill repeat_expression to 1 to match for this * now an rs_fill type frag. */ fragP->fr_offset = 1; break; } #endif /* I386 */ partial_bytes = nbytes - (repeat_expression * fill_size); /* * Now set the fr_offset to the fill repeat_expression * since this is now an rs_fill type. The fr_var is still * the fill_size. */ fragP->fr_offset = repeat_expression; /* * For rs_align frags there may be partial_bytes to fill * with zeros before we can fill with the fill_expression * of fill_size. When the rs_align frag was created it was * created with fill_size-1 extra bytes in the fixed part. */ if(partial_bytes != 0){ /* moved the fill_expression bytes foward */ memmove(fragP->fr_literal +fragP->fr_fix +partial_bytes, fragP->fr_literal +fragP->fr_fix, fragP->fr_var); /* zero out the partial_bytes */ memset(fragP->fr_literal + fragP->fr_fix, '\0', partial_bytes); /* adjust the fixed part of the frag */ fragP->fr_fix += partial_bytes; } break; case rs_fill: break; case rs_machine_dependent: md_convert_frag(fragP); /* * After md_convert_frag, we make the frag into a ".fill 0" * md_convert_frag() should set up any fixSs and constants * required. */ frag_wane(fragP); break; case rs_dwarf2dbg: dwarf2dbg_convert_frag(fragP); break; case rs_leb128: { int size; #ifdef OLD valueT value = S_GET_VALUE (fragP->fr_symbol); #else valueT value; expressionS *expression; if(fragP->fr_symbol->expression != NULL){ expression = (expressionS *)fragP->fr_symbol->expression; value = 0; if(expression->X_add_symbol != NULL) value += expression->X_add_symbol->sy_nlist.n_value; if(expression->X_subtract_symbol != NULL) value -= expression->X_subtract_symbol->sy_nlist.n_value; value += expression->X_add_number; } else{ value = fragP->fr_symbol->sy_nlist.n_value + fragP->fr_address; } #endif size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value, fragP->fr_subtype); fragP->fr_fix += size; fragP->fr_type = rs_fill; fragP->fr_var = 0; fragP->fr_offset = 0; fragP->fr_symbol = NULL; } break; default: BAD_CASE(fragP->fr_type); break; } } } /* * For each section do the fixups for the frags. */ for(frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next){ now_seg = frchainP->frch_nsect; fixup_section(frchainP->frch_fix_root, frchainP->frch_nsect); } }
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 (); } }
static void dot_cfi (int arg) { offsetT offset; unsigned reg1, reg2; if (frchain_now->frch_cfi_data == NULL) { as_bad (_("CFI instruction used without previous .cfi_startproc")); ignore_rest_of_line (); return; } /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) != frag_now_fix ()) cfi_add_advance_loc (symbol_temp_new_now ()); switch (arg) { case DW_CFA_offset: reg1 = cfi_parse_reg (); cfi_parse_separator (); offset = cfi_parse_const (); cfi_add_CFA_offset (reg1, offset); break; case CFI_rel_offset: reg1 = cfi_parse_reg (); cfi_parse_separator (); offset = cfi_parse_const (); cfi_add_CFA_offset (reg1, offset - frchain_now->frch_cfi_data->cur_cfa_offset); break; case DW_CFA_def_cfa: reg1 = cfi_parse_reg (); cfi_parse_separator (); offset = cfi_parse_const (); cfi_add_CFA_def_cfa (reg1, offset); break; case DW_CFA_register: reg1 = cfi_parse_reg (); cfi_parse_separator (); reg2 = cfi_parse_reg (); cfi_add_CFA_register (reg1, reg2); break; case DW_CFA_def_cfa_register: reg1 = cfi_parse_reg (); cfi_add_CFA_def_cfa_register (reg1); break; case DW_CFA_def_cfa_offset: offset = cfi_parse_const (); cfi_add_CFA_def_cfa_offset (offset); break; case CFI_adjust_cfa_offset: offset = cfi_parse_const (); cfi_add_CFA_def_cfa_offset (frchain_now->frch_cfi_data->cur_cfa_offset + offset); break; case DW_CFA_restore: for (;;) { reg1 = cfi_parse_reg (); cfi_add_CFA_restore (reg1); SKIP_WHITESPACE (); if (*input_line_pointer != ',') break; ++input_line_pointer; } break; case DW_CFA_undefined: for (;;) { reg1 = cfi_parse_reg (); cfi_add_CFA_undefined (reg1); SKIP_WHITESPACE (); if (*input_line_pointer != ',') break; ++input_line_pointer; } break; case DW_CFA_same_value: reg1 = cfi_parse_reg (); cfi_add_CFA_same_value (reg1); break; case CFI_return_column: reg1 = cfi_parse_reg (); cfi_set_return_column (reg1); break; case DW_CFA_remember_state: cfi_add_CFA_remember_state (); break; case DW_CFA_restore_state: cfi_add_CFA_restore_state (); break; case DW_CFA_GNU_window_save: cfi_add_CFA_insn (DW_CFA_GNU_window_save); break; case CFI_signal_frame: frchain_now->frch_cfi_data->cur_fde_data->signal_frame = 1; break; default: abort (); } demand_empty_rest_of_line (); }
static void process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; unsigned column = 0; unsigned isa = 0; unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; fragS *last_frag = NULL, *frag; addressT last_frag_ofs = 0, frag_ofs; symbolS *last_lab = NULL, *lab; struct line_entry *next; do { int line_delta; if (filenum != e->loc.filenum) { filenum = e->loc.filenum; out_opcode (DW_LNS_set_file); out_uleb128 (filenum); } if (column != e->loc.column) { column = e->loc.column; out_opcode (DW_LNS_set_column); out_uleb128 (column); } if (e->loc.discriminator != 0) { out_opcode (DW_LNS_extended_op); out_leb128 (1 + sizeof_leb128 (e->loc.discriminator, 0)); out_opcode (DW_LNE_set_discriminator); out_uleb128 (e->loc.discriminator); } if (isa != e->loc.isa) { isa = e->loc.isa; out_opcode (DW_LNS_set_isa); out_uleb128 (isa); } if ((e->loc.flags ^ flags) & DWARF2_FLAG_IS_STMT) { flags = e->loc.flags; out_opcode (DW_LNS_negate_stmt); } if (e->loc.flags & DWARF2_FLAG_BASIC_BLOCK) out_opcode (DW_LNS_set_basic_block); if (e->loc.flags & DWARF2_FLAG_PROLOGUE_END) out_opcode (DW_LNS_set_prologue_end); if (e->loc.flags & DWARF2_FLAG_EPILOGUE_BEGIN) out_opcode (DW_LNS_set_epilogue_begin); /* Don't try to optimize away redundant entries; gdb wants two entries for a function where the code starts on the same line as the {, and there's no way to identify that case here. Trust gcc to optimize appropriately. */ line_delta = e->loc.line - line; lab = e->label; frag = symbol_get_frag (lab); frag_ofs = S_GET_VALUE (lab); if (last_frag == NULL) { out_set_addr (lab); out_inc_line_addr (line_delta, 0); } else if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs); else relax_inc_line_addr (line_delta, lab, last_lab); line = e->loc.line; last_lab = lab; last_frag = frag; last_frag_ofs = frag_ofs; next = e->next; free (e); e = next; } while (e); /* Emit a DW_LNE_end_sequence for the end of the section. */ frag = last_frag_for_seg (seg); frag_ofs = get_frag_fix (frag, seg); if (frag == last_frag && ! DWARF2_USE_FIXED_ADVANCE_PC) out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs); else { lab = symbol_temp_new (seg, frag_ofs, frag); relax_inc_line_addr (INT_MAX, lab, last_lab); } }
static void list_symbol_table (void) { extern symbolS *symbol_rootP; int got_some = 0; symbolS *ptr; eject = 1; listing_page (NULL); for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) { if (SEG_NORMAL (S_GET_SEGMENT (ptr)) || S_GET_SEGMENT (ptr) == absolute_section) { /* Don't report section symbols. They are not interesting. */ if (symbol_section_p (ptr)) continue; if (S_GET_NAME (ptr)) { char buf[30], fmt[8]; valueT val = S_GET_VALUE (ptr); /* @@ Note that this is dependent on the compilation options, not solely on the target characteristics. */ if (sizeof (val) == 4 && sizeof (int) == 4) sprintf (buf, "%08lx", (unsigned long) val); else if (sizeof (val) <= sizeof (unsigned long)) { sprintf (fmt, "%%0%lulx", (unsigned long) (sizeof (val) * 2)); sprintf (buf, fmt, (unsigned long) val); } #if defined (BFD64) else if (sizeof (val) > 4) sprintf_vma (buf, val); #endif else abort (); if (!got_some) { fprintf (list_file, "DEFINED SYMBOLS\n"); on_page++; got_some = 1; } if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line) { fprintf (list_file, "%20s:%-5d %s:%s %s\n", symbol_get_frag (ptr)->line->file->filename, symbol_get_frag (ptr)->line->line, segment_name (S_GET_SEGMENT (ptr)), buf, S_GET_NAME (ptr)); } else { fprintf (list_file, "%33s:%s %s\n", segment_name (S_GET_SEGMENT (ptr)), buf, S_GET_NAME (ptr)); } on_page++; listing_page (NULL); } } } if (!got_some) { fprintf (list_file, "NO DEFINED SYMBOLS\n"); on_page++; } emit_line (NULL, "\n"); got_some = 0; for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) { if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0) { if (S_GET_SEGMENT (ptr) == undefined_section) { if (!got_some) { got_some = 1; emit_line (NULL, "UNDEFINED SYMBOLS\n"); } emit_line (NULL, "%s\n", S_GET_NAME (ptr)); } } } if (!got_some) emit_line (NULL, "NO UNDEFINED SYMBOLS\n"); }
static void dot_cfi_val_encoded_addr (int ignored ATTRIBUTE_UNUSED) { struct cfi_insn_data *insn_ptr; offsetT encoding; if (frchain_now->frch_cfi_data == NULL) { as_bad (_("CFI instruction used without previous .cfi_startproc")); ignore_rest_of_line (); return; } /* If the last address was not at the current PC, advance to current. */ if (symbol_get_frag (frchain_now->frch_cfi_data->last_address) != frag_now || S_GET_VALUE (frchain_now->frch_cfi_data->last_address) != frag_now_fix ()) cfi_add_advance_loc (symbol_temp_new_now ()); insn_ptr = alloc_cfi_insn_data (); insn_ptr->insn = CFI_val_encoded_addr; insn_ptr->u.ea.reg = cfi_parse_reg (); cfi_parse_separator (); encoding = cfi_parse_const (); if ((encoding & 0xff) != encoding || ((encoding & 0x70) != 0 #if CFI_DIFF_EXPR_OK || defined tc_cfi_emit_pcrel_expr && (encoding & 0x70) != DW_EH_PE_pcrel #endif ) /* leb128 can be handled, but does something actually need it? */ || (encoding & 7) == DW_EH_PE_uleb128 || (encoding & 7) > DW_EH_PE_udata8) { as_bad (_("invalid or unsupported encoding in .cfi_lsda")); encoding = DW_EH_PE_omit; } cfi_parse_separator (); expression_and_evaluate (&insn_ptr->u.ea.exp); switch (insn_ptr->u.ea.exp.X_op) { case O_symbol: break; case O_constant: if ((encoding & 0x70) != DW_EH_PE_pcrel) break; default: encoding = DW_EH_PE_omit; break; } insn_ptr->u.ea.encoding = encoding; if (encoding == DW_EH_PE_omit) { as_bad (_("wrong third argument to .cfi_val_encoded_addr")); ignore_rest_of_line (); return; } demand_empty_rest_of_line (); }
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 (); } }
void coff_frob_symbol (symbolS *symp, int *punt) { static symbolS *last_tagP; static stack *block_stack; static symbolS *set_end; symbolS *next_set_end = NULL; if (symp == &abs_symbol) { *punt = 1; return; } if (current_lineno_sym) coff_add_linesym (NULL); if (!block_stack) block_stack = stack_init (512, sizeof (symbolS*)); #ifdef TE_PE if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK && ! S_IS_WEAK (symp) && weak_is_altname (S_GET_NAME (symp))) { /* This is a weak alternate symbol. All processing of PECOFFweak symbols is done here, through the alternate. */ symbolS *weakp = symbol_find_noref (weak_altname2name (S_GET_NAME (symp)), 1); assert (weakp); assert (S_GET_NUMBER_AUXILIARY (weakp) == 1); if (! S_IS_WEAK (weakp)) { /* The symbol was turned from weak to strong. Discard altname. */ *punt = 1; return; } else if (symbol_equated_p (weakp)) { /* The weak symbol has an alternate specified; symp is unneeded. */ S_SET_STORAGE_CLASS (weakp, C_NT_WEAK); SA_SET_SYM_TAGNDX (weakp, symbol_get_value_expression (weakp)->X_add_symbol); S_CLEAR_EXTERNAL (symp); *punt = 1; return; } else { /* The weak symbol has been assigned an alternate value. Copy this value to symp, and set symp as weakp's alternate. */ if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK) { S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp)); S_SET_STORAGE_CLASS (weakp, C_NT_WEAK); } if (S_IS_DEFINED (weakp)) { /* This is a defined weak symbol. Copy value information from the weak symbol itself to the alternate symbol. */ symbol_set_value_expression (symp, symbol_get_value_expression (weakp)); symbol_set_frag (symp, symbol_get_frag (weakp)); S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp)); } else { /* This is an undefined weak symbol. Define the alternate symbol to zero. */ S_SET_VALUE (symp, 0); S_SET_SEGMENT (symp, absolute_section); } S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp))); S_SET_STORAGE_CLASS (symp, C_EXT); S_SET_VALUE (weakp, 0); S_SET_SEGMENT (weakp, undefined_section); } } #else /* TE_PE */ if (S_IS_WEAK (symp)) S_SET_STORAGE_CLASS (symp, C_WEAKEXT); #endif /* TE_PE */ if (!S_IS_DEFINED (symp) && !S_IS_WEAK (symp) && S_GET_STORAGE_CLASS (symp) != C_STAT) S_SET_STORAGE_CLASS (symp, C_EXT); if (!SF_GET_DEBUG (symp)) { symbolS * real; if (!SF_GET_LOCAL (symp) && !SF_GET_STATICS (symp) && S_GET_STORAGE_CLASS (symp) != C_LABEL && symbol_constant_p (symp) && (real = symbol_find_noref (S_GET_NAME (symp), 1)) && S_GET_STORAGE_CLASS (real) == C_NULL && real != symp) { c_symbol_merge (symp, real); *punt = 1; return; } if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp)) { assert (S_GET_VALUE (symp) == 0); if (S_IS_WEAKREFD (symp)) *punt = 1; else S_SET_EXTERNAL (symp); } else if (S_GET_STORAGE_CLASS (symp) == C_NULL) { if (S_GET_SEGMENT (symp) == text_section && symp != seg_info (text_section)->sym) S_SET_STORAGE_CLASS (symp, C_LABEL); else S_SET_STORAGE_CLASS (symp, C_STAT); } if (SF_GET_PROCESS (symp)) { if (S_GET_STORAGE_CLASS (symp) == C_BLOCK) { if (streq (S_GET_NAME (symp), ".bb")) stack_push (block_stack, (char *) &symp); else { symbolS *begin; begin = *(symbolS **) stack_pop (block_stack); if (begin == 0) as_warn (_("mismatched .eb")); else next_set_end = begin; } } if (coff_last_function == 0 && SF_GET_FUNCTION (symp)) { union internal_auxent *auxp; coff_last_function = symp; if (S_GET_NUMBER_AUXILIARY (symp) < 1) S_SET_NUMBER_AUXILIARY (symp, 1); auxp = SYM_AUXENT (symp); memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0, sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen)); } if (S_GET_STORAGE_CLASS (symp) == C_EFCN) { if (coff_last_function == 0) as_fatal (_("C_EFCN symbol for %s out of scope"), S_GET_NAME (symp)); SA_SET_SYM_FSIZE (coff_last_function, (long) (S_GET_VALUE (symp) - S_GET_VALUE (coff_last_function))); next_set_end = coff_last_function; coff_last_function = 0; } } if (S_IS_EXTERNAL (symp)) S_SET_STORAGE_CLASS (symp, C_EXT); else if (SF_GET_LOCAL (symp)) *punt = 1; if (SF_GET_FUNCTION (symp)) symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION; } /* Double check weak symbols. */ if (S_IS_WEAK (symp) && S_IS_COMMON (symp)) as_bad (_("Symbol `%s' can not be both weak and common"), S_GET_NAME (symp)); if (SF_GET_TAG (symp)) last_tagP = symp; else if (S_GET_STORAGE_CLASS (symp) == C_EOS) next_set_end = last_tagP; #ifdef OBJ_XCOFF /* This is pretty horrible, but we have to set *punt correctly in order to call SA_SET_SYM_ENDNDX correctly. */ if (! symbol_used_in_reloc_p (symp) && ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0 || (! (S_IS_EXTERNAL (symp) || S_IS_WEAK (symp)) && ! symbol_get_tc (symp)->output && S_GET_STORAGE_CLASS (symp) != C_FILE))) *punt = 1; #endif if (set_end != (symbolS *) NULL && ! *punt && ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0 || (S_IS_DEFINED (symp) && ! S_IS_COMMON (symp) && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp))))) { SA_SET_SYM_ENDNDX (set_end, symp); set_end = NULL; } if (next_set_end != NULL) { if (set_end != NULL) as_warn ("Warning: internal error: forgetting to set endndx of %s", S_GET_NAME (set_end)); set_end = next_set_end; } #ifndef OBJ_XCOFF if (! *punt && S_GET_STORAGE_CLASS (symp) == C_FCN && streq (S_GET_NAME (symp), ".bf")) { if (coff_last_bf != NULL) SA_SET_SYM_ENDNDX (coff_last_bf, symp); coff_last_bf = symp; } #endif if (coffsymbol (symbol_get_bfdsym (symp))->lineno) { int i; struct line_no *lptr; alent *l; lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno; for (i = 0; lptr; lptr = lptr->next) i++; lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno; /* We need i entries for line numbers, plus 1 for the first entry which BFD will override, plus 1 for the last zero entry (a marker for BFD). */ l = xmalloc ((i + 2) * sizeof (* l)); coffsymbol (symbol_get_bfdsym (symp))->lineno = l; l[i + 1].line_number = 0; l[i + 1].u.sym = NULL; for (; i > 0; i--) { if (lptr->frag) lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE; l[i] = lptr->l; lptr = lptr->next; } } }
static void nemaweaver_s_lcomm (int xxx ATTRIBUTE_UNUSED) { char *name; char c; char *p; offsetT size; symbolS *symbolP; offsetT align; char *pfrag; int align2; segT current_seg = now_seg; subsegT current_subseg = now_subseg; name = input_line_pointer; c = get_symbol_end (); /* Just after name is now '\0'. */ p = input_line_pointer; *p = c; SKIP_WHITESPACE (); if (*input_line_pointer != ',') { as_bad (_("Expected comma after symbol-name: rest of line ignored.")); ignore_rest_of_line (); return; } input_line_pointer++; /* skip ',' */ if ((size = get_absolute_expression ()) < 0) { as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); ignore_rest_of_line (); return; } /* The third argument to .lcomm is the alignment. */ if (*input_line_pointer != ',') align = 8; else { ++input_line_pointer; align = get_absolute_expression (); if (align <= 0) { as_warn (_("ignoring bad alignment")); align = 8; } } *p = 0; symbolP = symbol_find_or_make (name); *p = c; if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { as_bad (_("Ignoring attempt to re-define symbol `%s'."), S_GET_NAME (symbolP)); ignore_rest_of_line (); return; } if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) { as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), (long) size); ignore_rest_of_line (); return; } /* Allocate_bss. */ if (align) { /* Convert to a power of 2 alignment. */ for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); if (align != 1) { as_bad (_("Common alignment not a power of 2")); ignore_rest_of_line (); return; } } else