blob: 5f1255d4f678528bc574ef5048422d647d78bed8 [file] [log] [blame]
/* Mach-O object file format
Copyright 2009 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3,
or (at your option) any later version.
GAS is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#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)
{
char *name;
int c;
symbolS *symbolP;
do
{
/* Get symbol name. */
name = input_line_pointer;
c = get_symbol_end ();
symbolP = symbol_find_or_make (name);
S_SET_WEAK (symbolP);
*input_line_pointer = c;
SKIP_WHITESPACE ();
if (c != ',')
break;
input_line_pointer++;
SKIP_WHITESPACE ();
}
while (*input_line_pointer != '\n');
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},
{ "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}
};