/* write.c - emit .o file
- Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- 2010 Free Software Foundation, Inc.
+ Copyright (C) 1986-2018 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
-/* This thing should be set up to do byteordering correctly. But... */
+/* This thing should be set up to do byte ordering correctly. But... */
#include "as.h"
#include "subsegs.h"
#include "obstack.h"
#include "output-file.h"
#include "dwarf2dbg.h"
-#include "libbfd.h"
#include "compress-debug.h"
-#ifndef TC_ADJUST_RELOC_COUNT
-#define TC_ADJUST_RELOC_COUNT(FIX, COUNT)
-#endif
-
#ifndef TC_FORCE_RELOCATION
#define TC_FORCE_RELOCATION(FIX) \
(generic_force_reloc (FIX))
(TC_FORCE_RELOCATION (FIX))
#endif
-#ifndef TC_FORCE_RELOCATION_LOCAL
-#define TC_FORCE_RELOCATION_LOCAL(FIX) \
+#define GENERIC_FORCE_RELOCATION_LOCAL(FIX) \
(!(FIX)->fx_pcrel \
|| TC_FORCE_RELOCATION (FIX))
+#ifndef TC_FORCE_RELOCATION_LOCAL
+#define TC_FORCE_RELOCATION_LOCAL GENERIC_FORCE_RELOCATION_LOCAL
#endif
+#define GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \
+ (!SEG_NORMAL (SEG))
#ifndef TC_FORCE_RELOCATION_SUB_SAME
-#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \
- (! SEG_NORMAL (SEG))
+#define TC_FORCE_RELOCATION_SUB_SAME GENERIC_FORCE_RELOCATION_SUB_SAME
#endif
#ifndef md_register_arithmetic
/* Remember the value of dot when parsing expressions. */
addressT dot_value;
+/* The frag that dot_value is based from. */
+fragS *dot_frag;
+
/* Relocs generated by ".reloc" pseudo. */
struct reloc_list* reloc_list;
symbolS *sub_symbol, /* X_op_symbol. */
offsetT offset, /* X_add_number. */
int pcrel, /* TRUE if PC-relative relocation. */
- RELOC_ENUM r_type ATTRIBUTE_UNUSED /* Relocation type. */,
+ RELOC_ENUM r_type /* Relocation type. */,
int at_beginning) /* Add to the start of the list? */
{
fixS *fixP;
fixP->fx_subsy = sub_symbol;
fixP->fx_offset = offset;
fixP->fx_dot_value = dot_value;
+ fixP->fx_dot_frag = dot_frag;
fixP->fx_pcrel = pcrel;
fixP->fx_r_type = r_type;
fixP->fx_im_disp = 0;
TC_INIT_FIX_DATA (fixP);
#endif
- as_where (&fixP->fx_file, &fixP->fx_line);
+ fixP->fx_file = as_where (&fixP->fx_line);
{
segT seg,
/* Alignment, as a power of 2 (e.g., 1 => 2-byte
boundary, 2 => 4-byte boundary, etc.) */
- int align)
+ unsigned int align)
{
if (seg == absolute_section)
return;
- if ((unsigned int) align > bfd_get_section_alignment (stdoutput, seg))
+ if (align > bfd_get_section_alignment (stdoutput, seg))
bfd_set_section_alignment (stdoutput, seg, align);
}
prev_fix = frchp->fix_tail;
}
}
- gas_assert (prev_frag->fr_type != 0);
- gas_assert (prev_frag != &dummy);
+ gas_assert (prev_frag != &dummy
+ && prev_frag->fr_type != 0);
prev_frag->fr_next = 0;
return prev_frag;
}
{
switch (fragP->fr_type)
{
+ case rs_space_nop:
+ goto skip_align;
case rs_align:
case rs_align_code:
case rs_align_test:
#ifdef HANDLE_ALIGN
HANDLE_ALIGN (fragP);
#endif
+skip_align:
know (fragP->fr_next != NULL);
fragP->fr_offset = (fragP->fr_next->fr_address
- fragP->fr_address
if (fragP->fr_offset < 0)
{
as_bad_where (fragP->fr_file, fragP->fr_line,
- _("attempt to .org/.space backwards? (%ld)"),
+ _("attempt to .org/.space/.nops backwards? (%ld)"),
(long) fragP->fr_offset);
fragP->fr_offset = 0;
}
- fragP->fr_type = rs_fill;
+ if (fragP->fr_type == rs_space_nop)
+ fragP->fr_type = rs_fill_nop;
+ else
+ fragP->fr_type = rs_fill;
break;
case rs_fill:
+ case rs_fill_nop:
break;
case rs_leb128:
valueT value = S_GET_VALUE (fragP->fr_symbol);
int size;
+ if (!S_IS_DEFINED (fragP->fr_symbol))
+ {
+ as_bad_where (fragP->fr_file, fragP->fr_line,
+ _("leb128 operand is an undefined symbol: %s"),
+ S_GET_NAME (fragP->fr_symbol));
+ }
+
size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value,
fragP->fr_subtype);
x = bfd_set_section_flags (abfd, sec, flags);
gas_assert (x);
- newsize = md_section_align (sec, size);
+ /* If permitted, allow the backend to pad out the section
+ to some alignment boundary. */
+ if (do_not_pad_sections_to_alignment)
+ newsize = size;
+ else
+ newsize = md_section_align (sec, size);
x = bfd_set_section_size (abfd, sec, newsize);
gas_assert (x);
static void
resolve_reloc_expr_symbols (void)
{
+ bfd_vma addr_mask = 1;
struct reloc_list *r;
+ /* Avoid a shift by the width of type. */
+ addr_mask <<= bfd_arch_bits_per_address (stdoutput) - 1;
+ addr_mask <<= 1;
+ addr_mask -= 1;
+
for (r = reloc_list; r; r = r->next)
{
+ reloc_howto_type *howto = r->u.a.howto;
expressionS *symval;
symbolS *sym;
bfd_vma offset, addend;
asection *sec;
- reloc_howto_type *howto;
resolve_symbol_value (r->u.a.offset_sym);
symval = symbol_get_value_expression (r->u.a.offset_sym);
as_bad_where (r->file, r->line, _("invalid reloc expression"));
sec = NULL;
}
- else if (sym != NULL)
- symbol_mark_used_in_reloc (sym);
+ else if (sym != NULL && sec != NULL)
+ {
+ /* Convert relocs against local symbols to refer to the
+ corresponding section symbol plus offset instead. Keep
+ PC-relative relocs of the REL variety intact though to
+ prevent the offset from overflowing the relocated field,
+ unless it has enough bits to cover the whole address
+ space. */
+ if (S_IS_LOCAL (sym) && !symbol_section_p (sym)
+ && (sec->use_rela_p
+ || (howto->partial_inplace
+ && (!howto->pc_relative
+ || howto->src_mask == addr_mask))))
+ {
+ asection *symsec = S_GET_SEGMENT (sym);
+ if (!(((symsec->flags & SEC_MERGE) != 0
+ && addend != 0)
+ || (symsec->flags & SEC_THREAD_LOCAL) != 0))
+ {
+ addend += S_GET_VALUE (sym);
+ sym = section_symbol (symsec);
+ }
+ }
+ symbol_mark_used_in_reloc (sym);
+ }
}
if (sym == NULL)
{
sym = abs_section_sym;
}
- howto = r->u.a.howto;
-
r->u.b.sec = sec;
r->u.b.s = symbol_get_bfdsym (sym);
r->u.b.r.sym_ptr_ptr = &r->u.b.s;
if (symsec == NULL)
abort ();
- if (bfd_is_abs_section (symsec))
+ if (bfd_is_abs_section (symsec)
+ || symsec == reg_section)
{
/* The fixup_segment routine normally will not use this
symbol in a relocation. */
handled now. (These consist of fixS where we have since discovered
the value of a symbol, or the address of the frag involved.)
For each one, call md_apply_fix to put the fix into the frag data.
+ Ones that we couldn't completely handle here will be output later
+ by emit_relocations. */
- Result is a count of how many relocation structs will be needed to
- handle the remaining fixS's that we couldn't completely handle here.
- These will be output later by emit_relocations(). */
-
-static long
+static void
fixup_segment (fixS *fixP, segT this_segment)
{
- long seg_reloc_count = 0;
valueT add_number;
fragS *fragP;
segT add_symbol_segment = absolute_section;
symbol_mark_used_in_reloc (fixP->fx_addsy);
if (fixP->fx_subsy != NULL)
symbol_mark_used_in_reloc (fixP->fx_subsy);
- seg_reloc_count++;
}
- TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
- return seg_reloc_count;
+ return;
}
for (; fixP; fixP = fixP->fx_next)
{
add_number -= S_GET_VALUE (fixP->fx_subsy);
fixP->fx_offset = (add_number + fixP->fx_dot_value
- + fixP->fx_frag->fr_address);
+ + fixP->fx_dot_frag->fr_address);
/* Make it pc-relative. If the back-end code has not
selected a pc-relative reloc, cancel the adjustment
S_GET_NAME (fixP->fx_subsy),
segment_name (sub_symbol_segment));
}
+ else if (sub_symbol_segment != undefined_section
+ && ! bfd_is_com_section (sub_symbol_segment)
+ && MD_APPLY_SYM_VALUE (fixP))
+ add_number -= S_GET_VALUE (fixP->fx_subsy);
}
if (fixP->fx_addsy)
if (!fixP->fx_done)
{
- ++seg_reloc_count;
if (fixP->fx_addsy == NULL)
fixP->fx_addsy = abs_section_sym;
symbol_mark_used_in_reloc (fixP->fx_addsy);
else
sprintf (buf2, "%ld", (long) add_number);
as_bad_where (fixP->fx_file, fixP->fx_line,
- _("value of %s too large for field of %d bytes at %s"),
+ ngettext ("value of %s too large for field "
+ "of %d byte at %s",
+ "value of %s too large for field "
+ "of %d bytes at %s",
+ fixP->fx_size),
buf2, fixP->fx_size, buf);
} /* Generic error checking. */
}
print_fixup (fixP);
#endif
} /* For each fixS in this segment. */
-
- TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count);
- return seg_reloc_count;
}
static void
static void
install_reloc (asection *sec, arelent *reloc, fragS *fragp,
- char *file, unsigned int line)
+ const char *file, unsigned int line)
{
char *err;
bfd_reloc_status_type s;
}
}
+static fragS *
+get_frag_for_reloc (fragS *last_frag,
+ const segment_info_type *seginfo,
+ const struct reloc_list *r)
+{
+ fragS *f;
+
+ for (f = last_frag; f != NULL; f = f->fr_next)
+ if (f->fr_address <= r->u.b.r.address
+ && r->u.b.r.address < f->fr_address + f->fr_fix)
+ return f;
+
+ for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
+ if (f->fr_address <= r->u.b.r.address
+ && r->u.b.r.address < f->fr_address + f->fr_fix)
+ return f;
+
+ for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
+ if (f->fr_address <= r->u.b.r.address
+ && r->u.b.r.address <= f->fr_address + f->fr_fix)
+ return f;
+
+ as_bad_where (r->file, r->line,
+ _("reloc not within (fixed part of) section"));
+ return NULL;
+}
+
static void
write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
{
segment_info_type *seginfo = seg_info (sec);
- unsigned int i;
unsigned int n;
struct reloc_list *my_reloc_list, **rp, *r;
arelent **relocs;
fixS *fixp;
+ fragS *last_frag;
/* If seginfo is NULL, we did not create this section; don't do
anything with it. */
rp = &r->next;
}
- relocs = (arelent **) xcalloc (n, sizeof (arelent *));
+ relocs = XCNEWVEC (arelent *, n);
- i = 0;
+ n = 0;
+ r = my_reloc_list;
+ last_frag = NULL;
for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
{
- int j;
int fx_size, slack;
offsetT loc;
+ arelent **reloc;
+#ifndef RELOC_EXPANSION_POSSIBLE
+ arelent *rel;
+
+ reloc = &rel;
+#endif
if (fixp->fx_done)
continue;
_("internal error: fixup not contained within frag"));
#ifndef RELOC_EXPANSION_POSSIBLE
- {
- arelent *reloc = tc_gen_reloc (sec, fixp);
-
- if (!reloc)
- continue;
- relocs[i++] = reloc;
- j = 1;
- }
+ *reloc = tc_gen_reloc (sec, fixp);
#else
- {
- arelent **reloc = tc_gen_reloc (sec, fixp);
+ reloc = tc_gen_reloc (sec, fixp);
+#endif
- for (j = 0; reloc[j]; j++)
- relocs[i++] = reloc[j];
- }
+ while (*reloc)
+ {
+ while (r != NULL && r->u.b.r.address < (*reloc)->address)
+ {
+ fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+ if (f != NULL)
+ {
+ last_frag = f;
+ relocs[n++] = &r->u.b.r;
+ install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+ }
+ r = r->next;
+ }
+ relocs[n++] = *reloc;
+ install_reloc (sec, *reloc, fixp->fx_frag,
+ fixp->fx_file, fixp->fx_line);
+#ifndef RELOC_EXPANSION_POSSIBLE
+ break;
+#else
+ reloc++;
#endif
+ }
+ }
- for ( ; j != 0; --j)
- install_reloc (sec, relocs[i - j], fixp->fx_frag,
- fixp->fx_file, fixp->fx_line);
+ while (r != NULL)
+ {
+ fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+ if (f != NULL)
+ {
+ last_frag = f;
+ relocs[n++] = &r->u.b.r;
+ install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+ }
+ r = r->next;
}
- n = i;
#ifdef DEBUG4
{
}
#endif
- for (r = my_reloc_list; r != NULL; r = r->next)
- {
- fragS *f;
- for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
- if (f->fr_address <= r->u.b.r.address
- && r->u.b.r.address < f->fr_address + f->fr_fix)
- break;
- if (f == NULL)
- as_bad_where (r->file, r->line,
- _("reloc not within (fixed part of) section"));
- else
- {
- relocs[n++] = &r->u.b.r;
- install_reloc (sec, &r->u.b.r, f, r->file, r->line);
- }
- }
-
if (n)
{
flagword flags = bfd_get_section_flags (abfd, sec);
struct z_stream_s *strm;
int x;
flagword flags = bfd_get_section_flags (abfd, sec);
+ unsigned int header_size, compression_header_size;
if (seginfo == NULL
|| sec->size < 32
if (strm == NULL)
return;
- /* Create a new frag to contain the "ZLIB" header. */
+ if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+ {
+ compression_header_size
+ = bfd_get_compression_header_size (stdoutput, NULL);
+ header_size = compression_header_size;
+ }
+ else
+ {
+ compression_header_size = 0;
+ header_size = 12;
+ }
+
+ /* Create a new frag to contain the compression header. */
first_newf = frag_alloc (ob);
- if (obstack_room (ob) < 12)
+ if (obstack_room (ob) < header_size)
first_newf = frag_alloc (ob);
- if (obstack_room (ob) < 12)
- as_fatal (_("can't extend frag %u chars"), 12);
+ if (obstack_room (ob) < header_size)
+ as_fatal (ngettext ("can't extend frag %lu char",
+ "can't extend frag %lu chars",
+ (unsigned long) header_size),
+ (unsigned long) header_size);
last_newf = first_newf;
- obstack_blank_fast (ob, 12);
+ obstack_blank_fast (ob, header_size);
last_newf->fr_type = rs_fill;
- last_newf->fr_fix = 12;
+ last_newf->fr_fix = header_size;
header = last_newf->fr_literal;
- memcpy (header, "ZLIB", 4);
- header[11] = uncompressed_size; uncompressed_size >>= 8;
- header[10] = uncompressed_size; uncompressed_size >>= 8;
- header[9] = uncompressed_size; uncompressed_size >>= 8;
- header[8] = uncompressed_size; uncompressed_size >>= 8;
- header[7] = uncompressed_size; uncompressed_size >>= 8;
- header[6] = uncompressed_size; uncompressed_size >>= 8;
- header[5] = uncompressed_size; uncompressed_size >>= 8;
- header[4] = uncompressed_size;
- compressed_size = 12;
+ compressed_size = header_size;
/* Stream the frags through the compression engine, adding new frags
- as necessary to accomodate the compressed output. */
+ as necessary to accommodate the compressed output. */
for (f = seginfo->frchainP->frch_root;
f;
f = f->fr_next)
break;
}
+ /* PR binutils/18087: If compression didn't make the section smaller,
+ just keep it uncompressed. */
+ if (compressed_size >= uncompressed_size)
+ return;
+
/* Replace the uncompressed frag list with the compressed frag list. */
seginfo->frchainP->frch_root = first_newf;
seginfo->frchainP->frch_last = last_newf;
/* Update the section size and its name. */
+ bfd_update_compression_header (abfd, (bfd_byte *) header, sec);
x = bfd_set_section_size (abfd, sec, compressed_size);
gas_assert (x);
- compressed_name = (char *) xmalloc (strlen (section_name) + 2);
- compressed_name[0] = '.';
- compressed_name[1] = 'z';
- strcpy (compressed_name + 2, section_name + 1);
- bfd_section_name (stdoutput, sec) = compressed_name;
+ if (!compression_header_size)
+ {
+ compressed_name = concat (".z", section_name + 1, (char *) NULL);
+ bfd_section_name (stdoutput, sec) = compressed_name;
+ }
+}
+
+#ifndef md_generate_nops
+/* Genenerate COUNT bytes of no-op instructions to WHERE. A target
+ backend must override this with proper no-op instructions. */
+
+static void
+md_generate_nops (fragS *f ATTRIBUTE_UNUSED,
+ char *where ATTRIBUTE_UNUSED,
+ offsetT count ATTRIBUTE_UNUSED,
+ int control ATTRIBUTE_UNUSED)
+{
+ as_bad (_("unimplemented .nops directive"));
}
+#endif
static void
write_contents (bfd *abfd ATTRIBUTE_UNUSED,
char *fill_literal;
offsetT count;
- gas_assert (f->fr_type == rs_fill);
+ gas_assert (f->fr_type == rs_fill || f->fr_type == rs_fill_nop);
if (f->fr_fix)
{
x = bfd_set_section_contents (stdoutput, sec,
f->fr_literal, (file_ptr) offset,
(bfd_size_type) f->fr_fix);
if (!x)
- as_fatal (_("can't write %s: %s"), stdoutput->filename,
+ as_fatal (ngettext ("can't write %ld byte "
+ "to section %s of %s: '%s'",
+ "can't write %ld bytes "
+ "to section %s of %s: '%s'",
+ (long) f->fr_fix),
+ (long) f->fr_fix,
+ sec->name, stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += f->fr_fix;
}
- fill_literal = f->fr_literal + f->fr_fix;
+
fill_size = f->fr_var;
count = f->fr_offset;
+ fill_literal = f->fr_literal + f->fr_fix;
+
+ if (f->fr_type == rs_fill_nop)
+ {
+ gas_assert (count >= 0 && fill_size == 1);
+ if (count > 0)
+ {
+ char *buf = xmalloc (count);
+ md_generate_nops (f, buf, count, *fill_literal);
+ x = bfd_set_section_contents
+ (stdoutput, sec, buf, (file_ptr) offset,
+ (bfd_size_type) count);
+ if (!x)
+ as_fatal (ngettext ("can't fill %ld byte "
+ "in section %s of %s: '%s'",
+ "can't fill %ld bytes "
+ "in section %s of %s: '%s'",
+ (long) count), (long) count,
+ sec->name, stdoutput->filename,
+ bfd_errmsg (bfd_get_error ()));
+ offset += count;
+ free (buf);
+ }
+ continue;
+ }
+
gas_assert (count >= 0);
if (fill_size && count)
{
(file_ptr) offset,
(bfd_size_type) fill_size);
if (!x)
- as_fatal (_("can't write %s: %s"), stdoutput->filename,
+ as_fatal (ngettext ("can't fill %ld byte "
+ "in section %s of %s: '%s'",
+ "can't fill %ld bytes "
+ "in section %s of %s: '%s'",
+ (long) fill_size),
+ (long) fill_size,
+ sec->name, stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += fill_size;
}
(stdoutput, sec, buf, (file_ptr) offset,
(bfd_size_type) n_per_buf * fill_size);
if (!x)
- as_fatal (_("cannot write to output file '%s': %s"),
- stdoutput->filename,
+ as_fatal (ngettext ("can't fill %ld byte "
+ "in section %s of %s: '%s'",
+ "can't fill %ld bytes "
+ "in section %s of %s: '%s'",
+ (long) (n_per_buf * fill_size)),
+ (long) (n_per_buf * fill_size),
+ sec->name, stdoutput->filename,
bfd_errmsg (bfd_get_error ()));
offset += n_per_buf * fill_size;
}
}
/* Finish the subsegments. After every sub-segment, we fake an
- ".align ...". This conforms to BSD4.2 brane-damage. We then fake
+ ".align ...". This conforms to BSD4.2 brain-damage. We then fake
".fill 0" because that is the kind of frag that requires least
thought. ".align" frags like to have a following frag since that
makes calculating their intended length trivial. */
of the section. This allows proper nop-filling at the end of
code-bearing sections. */
#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) \
- (!(FRCHAIN)->frch_next ? get_recorded_alignment (SEG) : 0)
+ (!(FRCHAIN)->frch_next && subseg_text_p (SEG) \
+ && !do_not_pad_sections_to_alignment \
+ ? get_recorded_alignment (SEG) \
+ : 0)
#else
#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
#endif
#endif
-void
-subsegs_finish (void)
+static void
+subsegs_finish_section (asection *s)
{
struct frchain *frchainP;
- asection *s;
+ segment_info_type *seginfo = seg_info (s);
+ if (!seginfo)
+ return;
- for (s = stdoutput->sections; s; s = s->next)
+ for (frchainP = seginfo->frchainP;
+ frchainP != NULL;
+ frchainP = frchainP->frch_next)
{
- segment_info_type *seginfo = seg_info (s);
- if (!seginfo)
- continue;
+ int alignment;
- for (frchainP = seginfo->frchainP;
- frchainP != NULL;
- frchainP = frchainP->frch_next)
- {
- int alignment = 0;
+ subseg_set (s, frchainP->frch_subseg);
- subseg_set (s, frchainP->frch_subseg);
+ /* This now gets called even if we had errors. In that case,
+ any alignment is meaningless, and, moreover, will look weird
+ if we are generating a listing. */
+ if (had_errors ())
+ do_not_pad_sections_to_alignment = 1;
- /* This now gets called even if we had errors. In that case,
- any alignment is meaningless, and, moreover, will look weird
- if we are generating a listing. */
- if (!had_errors ())
- {
- alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
- if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
- && now_seg->entsize)
- {
- unsigned int entsize = now_seg->entsize;
- int entalign = 0;
+ alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
+ if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
+ && now_seg->entsize)
+ {
+ unsigned int entsize = now_seg->entsize;
+ int entalign = 0;
- while ((entsize & 1) == 0)
- {
- ++entalign;
- entsize >>= 1;
- }
- if (entalign > alignment)
- alignment = entalign;
- }
+ while ((entsize & 1) == 0)
+ {
+ ++entalign;
+ entsize >>= 1;
}
- if (subseg_text_p (now_seg))
- frag_align_code (alignment, 0);
- else
- frag_align (alignment, 0, 0);
+ if (entalign > alignment)
+ alignment = entalign;
+ }
- /* frag_align will have left a new frag.
- Use this last frag for an empty ".fill".
+ if (subseg_text_p (now_seg))
+ frag_align_code (alignment, 0);
+ else
+ frag_align (alignment, 0, 0);
- For this segment ...
- Create a last frag. Do not leave a "being filled in frag". */
- frag_wane (frag_now);
- frag_now->fr_fix = 0;
- know (frag_now->fr_next == NULL);
- }
+ /* frag_align will have left a new frag.
+ Use this last frag for an empty ".fill".
+
+ For this segment ...
+ Create a last frag. Do not leave a "being filled in frag". */
+ frag_wane (frag_now);
+ frag_now->fr_fix = 0;
+ know (frag_now->fr_next == NULL);
}
}
+static void
+subsegs_finish (void)
+{
+ asection *s;
+
+ for (s = stdoutput->sections; s; s = s->next)
+ subsegs_finish_section (s);
+}
+
+#ifdef OBJ_ELF
+static void
+create_obj_attrs_section (void)
+{
+ segT s;
+ char *p;
+ offsetT size;
+ const char *name;
+
+ size = bfd_elf_obj_attr_size (stdoutput);
+ if (size)
+ {
+ name = get_elf_backend_data (stdoutput)->obj_attrs_section;
+ if (!name)
+ name = ".gnu.attributes";
+ s = subseg_new (name, 0);
+ elf_section_type (s)
+ = get_elf_backend_data (stdoutput)->obj_attrs_section_type;
+ bfd_set_section_flags (stdoutput, s, SEC_READONLY | SEC_DATA);
+ frag_now_fix ();
+ p = frag_more (size);
+ bfd_elf_set_obj_attr_contents (stdoutput, (bfd_byte *)p, size);
+
+ subsegs_finish_section (s);
+ relax_segment (seg_info (s)->frchainP->frch_root, s, 0);
+ size_seg (stdoutput, s, NULL);
+ }
+}
+#endif
+
/* Write the object file. */
void
fragS *fragP; /* Track along all frags. */
#endif
- /* Do we really want to write it? */
- {
- int n_warns, n_errs;
- n_warns = had_warnings ();
- n_errs = had_errors ();
- /* The -Z flag indicates that an object file should be generated,
- regardless of warnings and errors. */
- if (flag_always_generate_output)
- {
- if (n_warns || n_errs)
- as_warn (_("%d error%s, %d warning%s, generating bad object file"),
- n_errs, n_errs == 1 ? "" : "s",
- n_warns, n_warns == 1 ? "" : "s");
- }
- else
- {
- if (n_errs)
- as_fatal (_("%d error%s, %d warning%s, no object file generated"),
- n_errs, n_errs == 1 ? "" : "s",
- n_warns, n_warns == 1 ? "" : "s");
- }
- }
+ subsegs_finish ();
+
+#ifdef md_pre_output_hook
+ md_pre_output_hook;
+#endif
+
+#ifdef md_pre_relax_hook
+ md_pre_relax_hook;
+#endif
/* From now on, we don't care about sub-segments. Build one frag chain
- for each segment. Linked thru fr_next. */
+ for each segment. Linked through fr_next. */
/* Remove the sections created by gas for its own purposes. */
{
/* Relaxation has completed. Freeze all syms. */
finalize_syms = 1;
+ dwarf2dbg_final_check ();
+
#ifdef md_post_relax_hook
md_post_relax_hook;
#endif
+#ifdef OBJ_ELF
+ if (IS_ELF)
+ create_obj_attrs_section ();
+#endif
+
#ifndef WORKING_DOT_WORD
{
struct broken_word *lie;
#ifdef TC_CONS_FIX_NEW
TC_CONS_FIX_NEW (lie->frag,
lie->word_goes_here - lie->frag->fr_literal,
- 2, &exp);
+ 2, &exp, TC_PARSE_CONS_RETURN_NONE);
#else
fix_new_exp (lie->frag,
lie->word_goes_here - lie->frag->fr_literal,
if (S_IS_COMMON (symp)
&& !TC_FAKE_LABEL (sname)
- && !S_IS_WEAKREFR (symp)
- && (!S_IS_EXTERNAL (symp) || S_IS_LOCAL (symp)))
+ && !S_IS_WEAKREFR (symp))
{
expressionS *e = symbol_get_value_expression (symp);
- as_bad (_("Local symbol `%s' can't be equated to common symbol `%s'"),
+ as_bad (_("`%s' can't be equated to common symbol `%s'"),
sname, S_GET_NAME (e->X_add_symbol));
}
if (S_GET_SEGMENT (symp) == reg_section)
obj_frob_file_after_relocs ();
#endif
+#if defined OBJ_ELF || defined OBJ_MAYBE_ELF
+ if (IS_ELF && flag_use_elf_stt_common)
+ stdoutput->flags |= BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON;
+#endif
+
/* Once all relocations have been written, we can compress the
contents of the debug sections. This needs to be done before
we start writing any sections, because it will affect the file
layout, which is fixed once we start writing contents. */
if (flag_compress_debug)
- bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+ {
+ if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+ stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+ else
+ stdoutput->flags |= BFD_COMPRESS;
+ bfd_map_over_sections (stdoutput, compress_debug, (char *) 0);
+ }
bfd_map_over_sections (stdoutput, write_contents, (char *) 0);
}
/* Relax_align. Advance location counter to next address that has 'alignment'
lowest order bits all 0s, return size of adjustment made. */
static relax_addressT
-relax_align (register relax_addressT address, /* Address now. */
- register int alignment /* Alignment (binary). */)
+relax_align (relax_addressT address, /* Address now. */
+ int alignment /* Alignment (binary). */)
{
relax_addressT mask;
relax_addressT new_address;
- mask = ~((~0) << alignment);
+ mask = ~((relax_addressT) ~0 << alignment);
new_address = (address + mask) & (~mask);
#ifdef LINKER_RELAXING_SHRINKS_ONLY
if (linkrelax)
if (offset % fragP->fr_var != 0)
{
as_bad_where (fragP->fr_file, fragP->fr_line,
- _("alignment padding (%lu bytes) not a multiple of %ld"),
+ ngettext ("alignment padding (%lu byte) "
+ "not a multiple of %ld",
+ "alignment padding (%lu bytes) "
+ "not a multiple of %ld",
+ (unsigned long) offset),
(unsigned long) offset, (long) fragP->fr_var);
offset -= (offset % fragP->fr_var);
}
break;
case rs_space:
+ case rs_space_nop:
break;
case rs_machine_dependent:
know (fragP->fr_next);
after = fragP->fr_next->fr_address + stretch;
growth = target - after;
- if (growth < 0)
+
+ /* Growth may be negative, but variable part of frag
+ cannot have fewer than 0 chars. That is, we can't
+ .org backwards. */
+ if (address + fragP->fr_fix > target)
{
growth = 0;
break;
}
- /* Growth may be negative, but variable part of frag
- cannot have fewer than 0 chars. That is, we can't
- .org backwards. */
as_bad_where (fragP->fr_file, fragP->fr_line,
_("attempt to move .org backwards"));
break;
case rs_space:
+ case rs_space_nop:
growth = 0;
if (symbolP)
{
}
as_warn_where (fragP->fr_file, fragP->fr_line,
- _(".space or .fill with negative value, ignored"));
+ _(".space, .nops or .fill with negative value, ignored"));
fragP->fr_symbol = 0;
}
else