diff --git a/gas/ChangeLog b/gas/ChangeLog index 110c77e9f0..e3d925f219 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2011-08-08 Tristan Gingold + + * config/obj-macho.c (obj_mach_o_section): New function. + (struct known_section): New type. + (known_sections): Declare. + (obj_mach_o_known_section): New function. + (obj_mach_o_common_parse): Ditto. + (obj_mach_o_comm): Ditto. + (obj_mach_o_subsections_via_symbols): Ditto. + (mach_o_pseudo_table): Add new pseudos. + 2011-08-06 Richard Henderson * dw2gencfi.c (all_fde_data): Export. diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c index ee19c4aa11..5f1255d4f6 100644 --- a/gas/config/obj-macho.c +++ b/gas/config/obj-macho.c @@ -21,7 +21,11 @@ #define OBJ_HEADER "obj-macho.h" #include "as.h" +#include "subsegs.h" +#include "symbols.h" +#include "write.h" #include "mach-o.h" +#include "mach-o/loader.h" static void obj_mach_o_weak (int ignore ATTRIBUTE_UNUSED) @@ -49,9 +53,258 @@ obj_mach_o_weak (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +/* Parse: + .section segname,sectname[,type[,attribute[,sizeof_stub]]] +*/ + +static void +obj_mach_o_section (int ignore ATTRIBUTE_UNUSED) +{ + char *p; + char *segname; + char *sectname; + char c; + int sectype = BFD_MACH_O_S_REGULAR; + unsigned int secattr = 0; + offsetT sizeof_stub = 0; + const char *name; + flagword oldflags, flags; + asection *sec; + + /* Parse segment name. */ + if (!is_name_beginner (*input_line_pointer)) + { + as_bad (_("missing segment name")); + ignore_rest_of_line (); + return; + } + p = input_line_pointer; + c = get_symbol_end (); + segname = alloca (input_line_pointer - p + 1); + strcpy (segname, p); + *input_line_pointer = c; + + if (*input_line_pointer != ',') + { + as_bad (_("missing comma after segment name")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + + /* Parse section name. */ + if (!is_name_beginner (*input_line_pointer)) + { + as_bad (_("missing section name")); + ignore_rest_of_line (); + return; + } + p = input_line_pointer; + c = get_symbol_end (); + sectname = alloca (input_line_pointer - p + 1); + strcpy (sectname, p); + *input_line_pointer = c; + + /* Parse type. */ + if (*input_line_pointer == ',') + { + input_line_pointer++; + if (!is_name_beginner (*input_line_pointer)) + { + as_bad (_("missing section type name")); + ignore_rest_of_line (); + return; + } + p = input_line_pointer; + c = get_symbol_end (); + + sectype = bfd_mach_o_get_section_type_from_name (p); + if (sectype == -1) + { + as_bad (_("unknown or invalid section type '%s'"), p); + sectype = BFD_MACH_O_S_REGULAR; + } + *input_line_pointer = c; + + /* Parse attributes. */ + if (*input_line_pointer == ',') + { + do + { + int attr; + + input_line_pointer++; + + if (!is_name_beginner (*input_line_pointer)) + { + as_bad (_("missing section attribute identifier")); + ignore_rest_of_line (); + break; + } + p = input_line_pointer; + c = get_symbol_end (); + + attr = bfd_mach_o_get_section_attribute_from_name (p); + if (attr == -1) + as_bad (_("unknown or invalid section attribute '%s'"), p); + else + secattr |= attr; + + *input_line_pointer = c; + } + while (*input_line_pointer == '+'); + + /* Parse sizeof_stub. */ + if (*input_line_pointer == ',') + { + if (sectype != BFD_MACH_O_S_SYMBOL_STUBS) + as_bad (_("unexpected sizeof_stub expression")); + + sizeof_stub = get_absolute_expression (); + } + else if (sectype == BFD_MACH_O_S_SYMBOL_STUBS) + as_bad (_("missing sizeof_stub expression")); + } + } + demand_empty_rest_of_line (); + + bfd_mach_o_normalize_section_name (segname, sectname, &name, &flags); + if (name == NULL) + { + /* There is no normal BFD section name for this section. Create one. + The name created doesn't really matter as it will never be written + on disk. */ + size_t seglen = strlen (segname); + size_t sectlen = strlen (sectname); + char *n; + + n = xmalloc (seglen + 1 + sectlen + 1); + memcpy (n, segname, seglen); + n[seglen] = '.'; + memcpy (n + seglen + 1, sectname, sectlen); + n[seglen + 1 + sectlen] = 0; + name = n; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* Sub-segments don't exists as is on Mach-O. */ + sec = subseg_new (name, 0); + + oldflags = bfd_get_section_flags (stdoutput, sec); + if (oldflags == SEC_NO_FLAGS) + { + bfd_mach_o_section *msect; + + if (! bfd_set_section_flags (stdoutput, sec, flags)) + as_warn (_("error setting flags for \"%s\": %s"), + bfd_section_name (stdoutput, sec), + bfd_errmsg (bfd_get_error ())); + msect = bfd_mach_o_get_mach_o_section (sec); + strncpy (msect->segname, segname, sizeof (msect->segname)); + msect->segname[16] = 0; + strncpy (msect->sectname, sectname, sizeof (msect->sectname)); + msect->sectname[16] = 0; + msect->flags = secattr | sectype; + msect->reserved2 = sizeof_stub; + } + else if (flags != SEC_NO_FLAGS) + { + if (flags != oldflags) + as_warn (_("Ignoring changed section attributes for %s"), name); + } +} + +struct known_section +{ + const char *name; + unsigned int flags; +}; + +static const struct known_section known_sections[] = + { + /* 0 */ { NULL, 0}, + /* 1 */ { ".cstring", BFD_MACH_O_S_CSTRING_LITERALS } + }; + +static void +obj_mach_o_known_section (int sect_index) +{ + const struct known_section *sect = &known_sections[sect_index]; + asection *old_sec; + segT sec; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + old_sec = bfd_get_section_by_name (stdoutput, sect->name); + if (old_sec) + { + /* Section already present. */ + sec = old_sec; + subseg_set (sec, 0); + } + else + { + bfd_mach_o_section *msect; + + sec = subseg_force_new (sect->name, 0); + + /* Set default flags. */ + msect = bfd_mach_o_get_mach_o_section (sec); + msect->flags = sect->flags; + } +} + +/* Called from read.c:s_comm after we've parsed .comm symbol, size. + Parse a possible alignment value. */ + +static symbolS * +obj_mach_o_common_parse (int ignore ATTRIBUTE_UNUSED, + symbolS *symbolP, addressT size) +{ + addressT align = 0; + + if (*input_line_pointer == ',') + { + align = parse_align (0); + if (align == (addressT) -1) + return NULL; + } + + S_SET_VALUE (symbolP, size); + S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); + + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; + + return symbolP; +} + +static void +obj_mach_o_comm (int ignore ATTRIBUTE_UNUSED) +{ + s_comm_internal (ignore, obj_mach_o_common_parse); +} + +static void +obj_mach_o_subsections_via_symbols (int arg ATTRIBUTE_UNUSED) +{ + /* Currently ignore it. */ + demand_empty_rest_of_line (); +} + const pseudo_typeS mach_o_pseudo_table[] = { - {"weak", obj_mach_o_weak, 0}, + { "weak", obj_mach_o_weak, 0}, + { "section", obj_mach_o_section, 0}, + { "cstring", obj_mach_o_known_section, 1}, + { "lcomm", s_lcomm, 1 }, + { "comm", obj_mach_o_comm, 0 }, + { "subsections_via_symbols", obj_mach_o_subsections_via_symbols, 0 }, {NULL, NULL, 0} };