aboutsummaryrefslogtreecommitdiff
path: root/gas/config/obj-coffbfd.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/obj-coffbfd.c')
-rw-r--r--gas/config/obj-coffbfd.c154
1 files changed, 109 insertions, 45 deletions
diff --git a/gas/config/obj-coffbfd.c b/gas/config/obj-coffbfd.c
index 38717af..b35d9cb 100644
--- a/gas/config/obj-coffbfd.c
+++ b/gas/config/obj-coffbfd.c
@@ -43,6 +43,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "../bfd/libbfd.h"
#include "../bfd/libcoff.h"
+/* The NOP_OPCODE is for the alignment fill value. Fill with nop so
+ that we can stick sections together without causing trouble. */
+#ifndef NOP_OPCODE
+#define NOP_OPCODE 0x00
+#endif
#define MIN(a,b) ((a) < (b)? (a) : (b))
/* This vector is used to turn an internal segment into a section #
@@ -96,7 +101,7 @@ bfd *abfd;
void EXFUN (bfd_as_write_hook, (struct internal_filehdr *,
bfd * abfd));
-static void EXFUN (fixup_segment, (fixS * fixP,
+static void EXFUN (fixup_segment, (segment_info_type *segP,
segT this_segment_type));
@@ -446,15 +451,7 @@ DEFUN (do_relocs_for, (abfd, file_cursor),
*file_cursor += external_reloc_size;
free (external_reloc_vec);
}
-#ifndef ZERO_BASED_SEGMENTS
- /* Supposedly setting segment addresses non-zero causes problems
- for some platforms, although it shouldn't. If you define
- ZERO_BASED_SEGMENTS, all the segments will be based at 0.
- Please don't make this the default, since some systems (e.g.,
- SVR3.2) require the segments to be non-zero based. Ian Taylor
- <ian@cygnus.com>. */
addr += segment_info[idx].scnhdr.s_size;
-#endif
}
}
@@ -470,6 +467,9 @@ DEFUN (fill_section, (abfd, filehdr, file_cursor),
{
unsigned int i;
+#ifdef ZERO_BASED_SEGMENTS
+ unsigned int paddr = 0;
+#endif
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
@@ -480,11 +480,22 @@ DEFUN (fill_section, (abfd, filehdr, file_cursor),
if (s->s_name[0])
{
fragS *frag = segment_info[i].frchainP->frch_root;
- char *buffer = malloc (s->s_size);
- if (s->s_size != 0)
- s->s_scnptr = *file_cursor;
+ char *buffer;
+
+ if (s->s_size != 0 && i != SEG_E2)
+ {
+ buffer = malloc (s->s_size);
+ s->s_scnptr = *file_cursor;
+#ifdef ZERO_BASED_SEGMENTS
+ s->s_paddr = paddr;
+ s->s_vaddr = paddr;
+#endif
+ }
else
- s->s_scnptr = 0;
+ {
+ buffer = NULL;
+ s->s_scnptr = 0;
+ }
s->s_flags = STYP_REG;
if (strcmp (s->s_name, ".text") == 0)
@@ -495,7 +506,10 @@ DEFUN (fill_section, (abfd, filehdr, file_cursor),
s->s_flags |= STYP_BSS | STYP_NOLOAD;
else if (strcmp (s->s_name, ".lit") == 0)
s->s_flags = STYP_LIT | STYP_TEXT;
-
+ else if (strcmp (s->s_name, ".init") == 0)
+ s->s_flags |= STYP_TEXT;
+ else if (strcmp (s->s_name, ".fini") == 0)
+ s->s_flags |= STYP_TEXT;
while (frag)
{
@@ -548,15 +562,17 @@ DEFUN (fill_section, (abfd, filehdr, file_cursor),
frag = frag->fr_next;
}
-
- bfd_write (buffer, s->s_size, 1, abfd);
- free (buffer);
-
- *file_cursor += s->s_size;
-
+ if (s->s_size != 0 && i != SEG_E2)
+ {
+ bfd_write (buffer, s->s_size, 1, abfd);
+ free (buffer);
+ *file_cursor += s->s_size;
+ }
+#ifdef ZERO_BASED_SEGMENTS
+ paddr += s->s_size;
+#endif
}
}
-
}
@@ -886,8 +902,8 @@ DEFUN_VOID (obj_coff_endef)
case C_FCN:
S_SET_SEGMENT (def_symbol_in_progress, SEG_E0);
- if (def_symbol_in_progress->sy_symbol.ost_entry._n._n_nptr[1][1] == 'b'
- && def_symbol_in_progress->sy_symbol.ost_entry._n._n_nptr[1][2] == 'f')
+ if (strcmp (def_symbol_in_progress->sy_symbol.ost_entry._n._n_nptr,
+ ".bf") == 0)
{ /* .bf */
if (function_lineoff < 0)
{
@@ -929,10 +945,14 @@ DEFUN_VOID (obj_coff_endef)
break;
} /* switch on storage class */
- /* Now that we have built a debug symbol, try to
- find if we should merge with an existing symbol
- or not. If a symbol is C_EFCN or SEG_ABSOLUTE or
- untagged SEG_DEBUG it never merges. */
+ /* Now that we have built a debug symbol, try to find if
+ we should merge with an existing symbol or not. If a
+ symbol is C_EFCN or SEG_ABSOLUTE or untagged
+ SEG_DEBUG it never merges. We also don't merge
+ labels, which are in a different namespace, nor
+ symbols which have not yet been defined since they
+ are typically unique, nor do we merge tags with
+ non-tags. */
/* Two cases for functions. Either debug followed
by definition or definition followed by debug.
@@ -950,10 +970,13 @@ DEFUN_VOID (obj_coff_endef)
leave an undefined symbol at link time. */
if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN
+ || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL
|| (S_GET_SEGMENT (def_symbol_in_progress) == SEG_DEBUG
&& !SF_GET_TAG (def_symbol_in_progress))
|| S_GET_SEGMENT (def_symbol_in_progress) == SEG_ABSOLUTE
- || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL)
+ || def_symbol_in_progress->sy_forward != NULL
+ || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL
+ || (SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP)))
{
symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP);
@@ -1207,9 +1230,22 @@ obj_coff_val ()
reference is solved, then copy the segment id
from the forward symbol. */
SF_SET_GET_SEGMENT (def_symbol_in_progress);
+
+ /* FIXME: gcc can generate address expressions
+ here in unusual cases (search for "obscure"
+ in sdbout.c). We just ignore the offset
+ here, thus generating incorrect debugging
+ information. We ignore the rest of the
+ line just below. */
}
- /* Otherwise, it is the name of a non debug symbol and its value will be calculated later. */
+ /* Otherwise, it is the name of a non debug symbol and
+ its value will be calculated later. */
*input_line_pointer = name_end;
+
+ /* FIXME: this is to avoid an error message in the
+ FIXME case mentioned just above. */
+ while (! is_end_of_line[*input_line_pointer])
+ ++input_line_pointer;
}
else
{
@@ -1260,7 +1296,6 @@ tag_find_or_make (name)
&zero_address_frag);
tag_insert (S_GET_NAME (symbolP), symbolP);
- symbol_table_insert (symbolP);
} /* not found */
return (symbolP);
@@ -1319,6 +1354,7 @@ DEFUN_VOID (yank_symbols)
/* L* and C_EFCN symbols never merge. */
if (!SF_GET_LOCAL (symbolP)
+ && S_GET_STORAGE_CLASS (symbolP) != C_LABEL
&& (real_symbolP = symbol_find_base (S_GET_NAME (symbolP), DO_NOT_STRIP))
&& real_symbolP != symbolP)
{
@@ -1789,8 +1825,10 @@ DEFUN_VOID (write_object_file)
frag */
subseg_new (frchain_ptr->frch_seg, frchain_ptr->frch_subseg);
+#ifndef SUB_SEGMENT_ALIGN
#define SUB_SEGMENT_ALIGN 1
- frag_align (SUB_SEGMENT_ALIGN, 0);
+#endif
+ frag_align (SUB_SEGMENT_ALIGN, NOP_OPCODE);
frag_wane (frag_now);
frag_now->fr_fix = 0;
know (frag_now->fr_next == NULL);
@@ -1819,19 +1857,30 @@ DEFUN_VOID (write_object_file)
filehdr.f_nscns++;
}
-#ifndef ZERO_BASED_SEGMENTS
- /* See the comment at the previous ZERO_BASED_SEGMENTS check. */
+ /* Supposedly setting segment addresses non-zero
+ causes problems for some platforms, although it
+ shouldn't. If you define ZERO_BASED_SEGMENTS, all
+ the segments will be based at 0. Please don't make
+ this the default, since some systems (e.g., SVR3.2)
+ require the segments to be non-zero based. Ian
+ Taylor <ian@cygnus.com>. */
+
if (i == SEG_E2)
{
/* This is a special case, we leave the size alone, which
will have been made up from all and any lcomms seen. */
+#ifndef ZERO_BASED_SEGMENTS
addr += segment_info[i].scnhdr.s_size;
+#endif
}
else
{
+#ifndef ZERO_BASED_SEGMENTS
addr += size_section (abfd, i);
- }
+#else
+ size_section (abfd, i);
#endif
+ }
}
@@ -1842,7 +1891,7 @@ DEFUN_VOID (write_object_file)
for (i = SEG_E0; i < SEG_UNKNOWN; i++)
{
fixup_mdeps (segment_info[i].frchainP->frch_root);
- fixup_segment (segment_info[i].fix_root, i);
+ fixup_segment (&segment_info[i], i);
}
#endif
@@ -1941,24 +1990,28 @@ DEFUN_VOID (obj_coff_section)
len = section_name_end - section_name;
input_line_pointer++;
SKIP_WHITESPACE ();
- if (c == ',')
+
+ /* Some 386 assemblers stick a quoted string at the end of
+ a .section; we just ignore it. */
+ if (c == ',' && *input_line_pointer != '"')
{
exp = get_absolute_expression ();
}
- else if (*input_line_pointer == ',')
+ else if (*input_line_pointer == ','
+ && input_line_pointer[1] != '"')
{
-
input_line_pointer++;
exp = get_absolute_expression ();
}
else
{
exp = 0;
+ while (! is_end_of_line[*input_line_pointer])
+ ++input_line_pointer;
}
change_to_section (section_name, len, exp);
*section_name_end = c;
-
}
@@ -2242,9 +2295,10 @@ DEFUN (fixup_mdeps, (frags),
#if 1
static void
DEFUN (fixup_segment, (fixP, this_segment_type),
- register fixS * fixP AND
+ segment_info_type * segP AND
segT this_segment_type)
{
+ register fixS * fixP;
register symbolS *add_symbolP;
register symbolS *sub_symbolP;
register long add_number;
@@ -2256,7 +2310,7 @@ DEFUN (fixup_segment, (fixP, this_segment_type),
register segT add_symbol_segment = SEG_ABSOLUTE;
- for (; fixP; fixP = fixP->fx_next)
+ for (fixP = segP->fix_root; fixP; fixP = fixP->fx_next)
{
fragP = fixP->fx_frag;
know (fragP);
@@ -2365,6 +2419,11 @@ DEFUN (fixup_segment, (fixP, this_segment_type),
add_number += S_GET_VALUE (add_symbolP);
add_number -= md_pcrel_from (fixP);
+#ifdef TC_I386
+ /* On the 386 we must adjust by the segment
+ vaddr as well. Ian Taylor. */
+ add_number -= segP->scnhdr.s_vaddr;
+#endif
pcrel = 0; /* Lie. Don't want further pcrel processing. */
fixP->fx_addsy = NULL; /* No relocations please. */
}
@@ -2402,10 +2461,10 @@ DEFUN (fixup_segment, (fixP, this_segment_type),
#endif /* TC_I960 */
#ifdef TC_I386
/* 386 COFF uses a peculiar format in
- which the value of a common symbol is
- stored in the .text segment (I've
- checked this on SVR3.2 and SCO 3.2.2)
- Ian Taylor <ian@cygnus.com>. */
+ which the value of a common symbol is
+ stored in the .text segment (I've
+ checked this on SVR3.2 and SCO 3.2.2)
+ Ian Taylor <ian@cygnus.com>. */
add_number += S_GET_VALUE (add_symbolP);
#endif
break;
@@ -2422,6 +2481,11 @@ DEFUN (fixup_segment, (fixP, this_segment_type),
{
fixP->fx_addsy = &abs_symbol;
} /* if there's an add_symbol */
+#ifdef TC_I386
+ /* On the 386 we must adjust by the segment vaddr
+ as well. Ian Taylor. */
+ add_number -= segP->scnhdr.s_vaddr;
+#endif
} /* if pcrel */
if (!fixP->fx_bit_fixP)