/* ELF object file format
- Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 1999
- Free Software Foundation, Inc.
+ Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
static void obj_elf_ident PARAMS ((int));
static void obj_elf_weak PARAMS ((int));
static void obj_elf_local PARAMS ((int));
-static void obj_elf_common PARAMS ((int));
+static void obj_elf_visibility PARAMS ((int));
static void obj_elf_symver PARAMS ((int));
static void obj_elf_vtable_inherit PARAMS ((int));
static void obj_elf_vtable_entry PARAMS ((int));
-static void obj_elf_data PARAMS ((int));
-static void obj_elf_text PARAMS ((int));
static void obj_elf_subsection PARAMS ((int));
+static void obj_elf_popsection PARAMS ((int));
static const pseudo_typeS elf_pseudo_table[] =
{
{"comm", obj_elf_common, 0},
+ {"common", obj_elf_common, 1},
{"ident", obj_elf_ident, 0},
{"local", obj_elf_local, 0},
{"previous", obj_elf_previous, 0},
{"section.s", obj_elf_section, 0},
{"sect", obj_elf_section, 0},
{"sect.s", obj_elf_section, 0},
+ {"pushsection", obj_elf_section, 1},
+ {"popsection", obj_elf_popsection, 0},
{"size", obj_elf_size, 0},
{"type", obj_elf_type, 0},
{"version", obj_elf_version, 0},
{"weak", obj_elf_weak, 0},
+ /* These define symbol visibility. */
+ {"internal", obj_elf_visibility, STV_INTERNAL},
+ {"hidden", obj_elf_visibility, STV_HIDDEN},
+ {"protected", obj_elf_visibility, STV_PROTECTED},
+
/* These are used for stabs-in-elf configurations. */
{"line", obj_elf_line, 0},
{"text", obj_elf_text, 0},
/* End sentinel. */
- {NULL},
+ {NULL, NULL, 0},
};
static const pseudo_typeS ecoff_debug_pseudo_table[] =
{ "vreg", s_ignore, 0 },
#endif
- {NULL} /* end sentinel */
+ {NULL, NULL, 0} /* end sentinel */
};
#undef NO_RELOC
#endif
}
-static void
-obj_elf_common (ignore)
- int ignore;
+void
+obj_elf_common (is_common)
+ int is_common;
{
char *name;
char c;
symbolS *symbolP;
int have_align;
+ if (flag_mri && is_common)
+ {
+ s_mri_common (0);
+ return;
+ }
+
name = input_line_pointer;
c = get_symbol_end ();
/* just after name is now '\0' */
}
if (S_GET_VALUE (symbolP) != 0)
{
- if (S_GET_VALUE (symbolP) != size)
+ if (S_GET_VALUE (symbolP) != (valueT) size)
{
as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."),
S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size);
static void
obj_elf_local (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
int c;
static void
obj_elf_weak (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
int c;
demand_empty_rest_of_line ();
}
+static void
+obj_elf_visibility (visibility)
+ int visibility;
+{
+ char *name;
+ int c;
+ symbolS *symbolP;
+ asymbol *bfdsym;
+ elf_symbol_type *elfsym;
+
+ do
+ {
+ name = input_line_pointer;
+ c = get_symbol_end ();
+ symbolP = symbol_find_or_make (name);
+ *input_line_pointer = c;
+
+ SKIP_WHITESPACE ();
+
+ bfdsym = symbol_get_bfdsym (symbolP);
+ elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym);
+
+ assert (elfsym);
+
+ elfsym->internal_elf_sym.st_other = visibility;
+
+ if (c == ',')
+ {
+ input_line_pointer ++;
+
+ SKIP_WHITESPACE ();
+
+ if (*input_line_pointer == '\n')
+ c = '\n';
+ }
+ }
+ while (c == ',');
+
+ demand_empty_rest_of_line ();
+}
+
+
static segT previous_section;
static int previous_subsection;
+struct section_stack
+{
+ struct section_stack *next;
+ segT seg, prev_seg;
+ int subseg, prev_subseg;
+};
+
+static struct section_stack *section_stack;
+
+
/* Handle the .section pseudo-op. This code supports two different
syntaxes.
int attributes;
};
-static struct special_section special_sections[] =
+static struct special_section const special_sections[] =
{
{ ".bss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ ".comment", SHT_PROGBITS, 0 },
};
void
-obj_elf_section (xxx)
- int xxx;
+obj_elf_change_section (name, type, attr, push)
+ char *name;
+ int type, attr, push;
{
- char *string;
int new_sec;
segT sec;
- int type, attr;
- int i;
- flagword flags;
- symbolS *secsym;
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
+ /* Switch to the section, creating it if necessary. */
+ if (push)
+ {
+ struct section_stack *elt;
+ elt = xmalloc (sizeof (struct section_stack));
+ elt->next = section_stack;
+ elt->seg = now_seg;
+ elt->prev_seg = previous_section;
+ elt->subseg = now_subseg;
+ elt->prev_subseg = previous_subsection;
+ section_stack = elt;
+ }
+ previous_section = now_seg;
+ previous_subsection = now_subseg;
+
+ new_sec = bfd_get_section_by_name (stdoutput, name) == NULL;
+ sec = subseg_new (name, 0);
+
+ if (new_sec)
+ {
+ flagword flags;
+ symbolS *secsym;
+ int i;
+
+ /* See if this is one of the special sections. */
+ for (i = 0; special_sections[i].name != NULL; i++)
+ if (strcmp (name, special_sections[i].name) == 0)
+ {
+ if (type == SHT_NULL)
+ type = special_sections[i].type;
+ else if (type != special_sections[i].type)
+ as_warn (_("Setting incorrect section type for %s"), name);
+
+ if ((attr &~ special_sections[i].attributes) != 0)
+ {
+ /* As a GNU extension, we permit a .note section to be
+ allocatable. If the linker sees an allocateable .note
+ section, it will create a PT_NOTE segment in the output
+ file. */
+ if (strcmp (name, ".note") != 0
+ || attr != SHF_ALLOC)
+ as_warn (_("Setting incorrect section attributes for %s"),
+ name);
+ }
+ attr |= special_sections[i].attributes;
+ break;
+ }
+
+ /* Convert ELF type and flags to BFD flags. */
+ flags = (SEC_RELOC
+ | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
+ | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
+ | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
+ | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0));
+#ifdef md_elf_section_flags
+ flags = md_elf_section_flags (flags, attr, type);
+#endif
+
+ /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */
+ if (type == SHT_NOBITS)
+ seg_info (sec)->bss = 1;
+
+ bfd_set_section_flags (stdoutput, sec, flags);
+
+ /* Add a symbol for this section to the symbol table. */
+ secsym = symbol_find (name);
+ if (secsym != NULL)
+ symbol_set_bfdsym (secsym, sec->symbol);
+ else
+ symbol_table_insert (section_symbol (sec));
+ }
+
+#ifdef md_elf_section_change_hook
+ md_elf_section_change_hook ();
+#endif
+}
+
+int
+obj_elf_parse_section_letters (str, len)
+ char *str;
+ size_t len;
+{
+ int attr = 0;
+
+ while (len > 0)
+ {
+ switch (*str)
+ {
+ case 'a':
+ attr |= SHF_ALLOC;
+ break;
+ case 'w':
+ attr |= SHF_WRITE;
+ break;
+ case 'x':
+ attr |= SHF_EXECINSTR;
+ break;
+ default:
+ {
+ char *bad_msg = _("Unrecognized .section attribute: want a,w,x");
+#ifdef md_elf_section_letter
+ int md_attr = md_elf_section_letter (*str, &bad_msg);
+ if (md_attr >= 0)
+ attr |= md_attr;
+ else
+#endif
+ {
+ as_warn (bad_msg);
+ attr = -1;
+ }
+ }
+ break;
+ }
+ str++, len--;
+ }
+
+ return attr;
+}
+
+int
+obj_elf_section_word (str, len)
+ char *str;
+ size_t len;
+{
+ if (len == 5 && strncmp (str, "write", 5) == 0)
+ return SHF_WRITE;
+ if (len == 5 && strncmp (str, "alloc", 5) == 0)
+ return SHF_ALLOC;
+ if (len == 9 && strncmp (str, "execinstr", 9) == 0)
+ return SHF_EXECINSTR;
+
+#ifdef md_elf_section_word
+ {
+ int md_attr = md_elf_section_word (str, len);
+ if (md_attr >= 0)
+ return md_attr;
+ }
+#endif
+
+ as_warn (_("Unrecognized section attribute"));
+ return 0;
+}
+
+int
+obj_elf_section_type (str, len)
+ char *str;
+ size_t len;
+{
+ if (len == 8 && strncmp (str, "progbits", 8) == 0)
+ return SHT_PROGBITS;
+ if (len == 6 && strncmp (str, "nobits", 6) == 0)
+ return SHT_NOBITS;
+
+#ifdef md_elf_section_type
+ {
+ int md_type = md_elf_section_type (str, len);
+ if (md_type >= 0)
+ return md_type;
+ }
+#endif
+
+ as_warn (_("Unrecognized section type"));
+ return 0;
+}
+
+void
+obj_elf_section (push)
+ int push;
+{
+ char *name, *beg, *end;
+ int type, attr, dummy;
+
if (flag_mri)
{
char mri_type;
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
previous_section = now_seg;
previous_subsection = now_subseg;
SKIP_WHITESPACE ();
if (*input_line_pointer == '"')
{
- string = demand_copy_C_string (&xxx);
- if (string == NULL)
+ name = demand_copy_C_string (&dummy);
+ if (name == NULL)
{
ignore_rest_of_line ();
return;
}
else
{
- char *p = input_line_pointer;
- char c;
- while (0 == strchr ("\n\t,; ", *p))
- p++;
- if (p == input_line_pointer)
+ end = input_line_pointer;
+ while (0 == strchr ("\n\t,; ", *end))
+ end++;
+ if (end == input_line_pointer)
{
as_warn (_("Missing section name"));
ignore_rest_of_line ();
return;
}
- c = *p;
- *p = 0;
- string = xmalloc ((unsigned long) (p - input_line_pointer + 1));
- strcpy (string, input_line_pointer);
- *p = c;
- input_line_pointer = p;
+
+ name = xmalloc (end - input_line_pointer + 1);
+ memcpy (name, input_line_pointer, end - input_line_pointer);
+ name[end - input_line_pointer] = '\0';
+ input_line_pointer = end;
}
-
- /* Switch to the section, creating it if necessary. */
- previous_section = now_seg;
- previous_subsection = now_subseg;
-
- new_sec = bfd_get_section_by_name (stdoutput, string) == NULL;
- sec = subseg_new (string, 0);
-
- /* If this section already existed, we don't bother to change the
- flag values. */
- if (! new_sec)
- {
- while (! is_end_of_line[(unsigned char) *input_line_pointer])
- ++input_line_pointer;
- ++input_line_pointer;
-
-#ifdef md_elf_section_change_hook
- md_elf_section_change_hook ();
-#endif
-
- return;
- }
-
SKIP_WHITESPACE ();
type = SHT_NULL;
{
/* Skip the comma. */
++input_line_pointer;
-
SKIP_WHITESPACE ();
if (*input_line_pointer == '"')
{
- /* Pick up a string with a combination of a, w, x. */
- ++input_line_pointer;
- while (*input_line_pointer != '"')
+ beg = demand_copy_C_string (&dummy);
+ if (beg == NULL)
{
- switch (*input_line_pointer)
- {
- case 'a':
- attr |= SHF_ALLOC;
- break;
- case 'w':
- attr |= SHF_WRITE;
- break;
- case 'x':
- attr |= SHF_EXECINSTR;
- break;
- default:
- {
- char *bad_msg = _("Bad .section directive: want a,w,x in string");
-#ifdef md_elf_section_letter
- int md_attr = md_elf_section_letter (*input_line_pointer, &bad_msg);
- if (md_attr)
- attr |= md_attr;
- else
-#endif
- {
- as_warn (bad_msg);
- ignore_rest_of_line ();
- return;
- }
- }
- }
- ++input_line_pointer;
+ ignore_rest_of_line ();
+ return;
}
-
- /* Skip the closing quote. */
- ++input_line_pointer;
+ attr |= obj_elf_parse_section_letters (beg, strlen (beg));
SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
+ char c;
++input_line_pointer;
SKIP_WHITESPACE ();
- if (*input_line_pointer == '@' || *input_line_pointer == '%')
+ c = *input_line_pointer;
+ if (c == '"')
{
- ++input_line_pointer;
- if (strncmp (input_line_pointer, "progbits",
- sizeof "progbits" - 1) == 0)
- {
- type = SHT_PROGBITS;
- input_line_pointer += sizeof "progbits" - 1;
- }
- else if (strncmp (input_line_pointer, "nobits",
- sizeof "nobits" - 1) == 0)
+ beg = demand_copy_C_string (&dummy);
+ if (beg == NULL)
{
- type = SHT_NOBITS;
- input_line_pointer += sizeof "nobits" - 1;
- }
- else
- {
-#ifdef md_elf_section_type
- int md_type = md_elf_section_type (&input_line_pointer);
- if (md_type)
- type = md_type;
- else
-#endif
- {
- as_warn (_("Unrecognized section type"));
- ignore_rest_of_line ();
- }
+ ignore_rest_of_line ();
+ return;
}
+ type = obj_elf_section_type (beg, strlen (beg));
+ }
+ else if (c == '@' || c == '%')
+ {
+ beg = ++input_line_pointer;
+ c = get_symbol_end ();
+ *input_line_pointer = c;
+ type = obj_elf_section_type (beg, input_line_pointer - beg);
}
}
}
{
do
{
+ char c;
+
SKIP_WHITESPACE ();
if (*input_line_pointer != '#')
{
ignore_rest_of_line ();
return;
}
- ++input_line_pointer;
- if (strncmp (input_line_pointer, "write",
- sizeof "write" - 1) == 0)
- {
- attr |= SHF_WRITE;
- input_line_pointer += sizeof "write" - 1;
- }
- else if (strncmp (input_line_pointer, "alloc",
- sizeof "alloc" - 1) == 0)
- {
- attr |= SHF_ALLOC;
- input_line_pointer += sizeof "alloc" - 1;
- }
- else if (strncmp (input_line_pointer, "execinstr",
- sizeof "execinstr" - 1) == 0)
- {
- attr |= SHF_EXECINSTR;
- input_line_pointer += sizeof "execinstr" - 1;
- }
- else
- {
-#ifdef md_elf_section_word
- int md_attr = md_elf_section_word (&input_line_pointer);
- if (md_attr)
- attr |= md_attr;
- else
-#endif
- {
- as_warn (_("Unrecognized section attribute"));
- ignore_rest_of_line ();
- return;
- }
- }
+ beg = ++input_line_pointer;
+ c = get_symbol_end ();
+ *input_line_pointer = c;
+
+ attr |= obj_elf_section_word (beg, input_line_pointer - beg);
+
SKIP_WHITESPACE ();
}
while (*input_line_pointer++ == ',');
}
}
- /* See if this is one of the special sections. */
- for (i = 0; special_sections[i].name != NULL; i++)
- {
- if (string[1] == special_sections[i].name[1]
- && strcmp (string, special_sections[i].name) == 0)
- {
- if (type == SHT_NULL)
- type = special_sections[i].type;
- else if (type != special_sections[i].type)
- as_warn (_("Setting incorrect section type for %s"), string);
-
- if ((attr &~ special_sections[i].attributes) != 0)
- {
- /* As a GNU extension, we permit a .note section to be
- allocatable. If the linker sees an allocateable
- .note section, it will create a PT_NOTE segment in
- the output file. */
- if (strcmp (string, ".note") != 0
- || attr != SHF_ALLOC)
- as_warn (_("Setting incorrect section attributes for %s"),
- string);
- }
- attr |= special_sections[i].attributes;
-
- break;
- }
- }
-
- flags = (SEC_RELOC
- | ((attr & SHF_WRITE) ? 0 : SEC_READONLY)
- | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0)
- | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0)
- | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0));
- if (special_sections[i].name == NULL)
- {
- if (type == SHT_PROGBITS)
- flags |= SEC_ALLOC | SEC_LOAD;
- else if (type == SHT_NOBITS)
- {
- flags |= SEC_ALLOC;
- flags &=~ SEC_LOAD;
- }
-
-#ifdef md_elf_section_flags
- flags = md_elf_section_flags (flags, attr, type);
-#endif
- }
-
- /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */
- if (type == SHT_NOBITS)
- seg_info (sec)->bss = 1;
-
- bfd_set_section_flags (stdoutput, sec, flags);
-
- /* Add a symbol for this section to the symbol table. */
- secsym = symbol_find (string);
- if (secsym != NULL)
- symbol_set_bfdsym (secsym, sec->symbol);
- else
- symbol_table_insert (section_symbol (sec));
-
-#ifdef md_elf_section_change_hook
- md_elf_section_change_hook ();
-#endif
-
demand_empty_rest_of_line ();
+
+ obj_elf_change_section (name, type, attr, push);
}
/* Change to the .data section. */
-static void
+void
obj_elf_data (i)
int i;
{
/* Change to the .text section. */
-static void
+void
obj_elf_text (i)
int i;
{
static void
obj_elf_subsection (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
register int temp;
void
obj_elf_previous (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
+ segT new_section;
+ int new_subsection;
+
if (previous_section == 0)
{
as_bad (_(".previous without corresponding .section; ignored"));
md_flush_pending_output ();
#endif
- subseg_set (previous_section, previous_subsection);
- previous_section = 0;
+ new_section = previous_section;
+ new_subsection = previous_subsection;
+ previous_section = now_seg;
+ previous_subsection = now_subseg;
+ subseg_set (new_section, new_subsection);
+
+#ifdef md_elf_section_change_hook
+ md_elf_section_change_hook ();
+#endif
+}
+
+static void
+obj_elf_popsection (xxx)
+ int xxx ATTRIBUTE_UNUSED;
+{
+ struct section_stack *top = section_stack;
+
+ if (top == NULL)
+ {
+ as_bad (_(".popsection without corresponding .pushsection; ignored"));
+ return;
+ }
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ section_stack = top->next;
+ previous_section = top->prev_seg;
+ previous_subsection = top->prev_subseg;
+ subseg_set (top->seg, top->subseg);
+ free (top);
#ifdef md_elf_section_change_hook
md_elf_section_change_hook ();
static void
obj_elf_line (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
/* Assume delimiter is part of expression. BSD4.2 as fails with
delightful bug, so we are not being incompatible here. */
static void
obj_elf_symver (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
char c;
static void
obj_elf_vtable_inherit (ignore)
+ int ignore ATTRIBUTE_UNUSED;
{
char *cname, *pname;
symbolS *csym, *psym;
static void
obj_elf_vtable_entry (ignore)
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
symbolS *sym;
void
obj_elf_version (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
unsigned int c;
static void
obj_elf_size (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name = input_line_pointer;
char c = get_symbol_end ();
static void
obj_elf_type (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
char *name;
char c;
static void
obj_elf_ident (ignore)
- int ignore;
+ int ignore ATTRIBUTE_UNUSED;
{
static segT comment_section;
segT old_section = now_seg;
int old_subsection = now_subseg;
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
if (!comment_section)
{
char *p;
adjust_stab_sections (abfd, sec, xxx)
bfd *abfd;
asection *sec;
- PTR xxx;
+ PTR xxx ATTRIBUTE_UNUSED;
{
char *name;
asection *strsec;
/*ARGSUSED*/
static void
elf_set_index (sym, indx)
- asymbol *sym;
- bfd_size_type indx;
+ asymbol *sym ATTRIBUTE_UNUSED;
+ bfd_size_type indx ATTRIBUTE_UNUSED;
{
}
this? */
sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap);
- if (! bfd_set_section_contents (stdoutput, sec, (PTR) NULL,
+ /* Pass BUF to bfd_set_section_contents because this will
+ eventually become a call to fwrite, and ISO C prohibits
+ passing a NULL pointer to a stdio function even if the
+ pointer will not be used. */
+ if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf,
(file_ptr) 0, (bfd_size_type) 0))
as_fatal (_("Can't start writing .mdebug section: %s"),
bfd_errmsg (bfd_get_error ()));