2011-08-08 Tristan Gingold <gingold@adacore.com>
[external/binutils.git] / gas / config / obj-macho.c
1 /* Mach-O object file format
2    Copyright 2009 Free Software Foundation, Inc.
3
4    This file is part of GAS, the GNU Assembler.
5
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as
8    published by the Free Software Foundation; either version 3,
9    or (at your option) any later version.
10
11    GAS is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14    the GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to the Free
18    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19    02110-1301, USA.  */
20
21 #define OBJ_HEADER "obj-macho.h"
22
23 #include "as.h"
24 #include "subsegs.h"
25 #include "symbols.h"
26 #include "write.h"
27 #include "mach-o.h"
28 #include "mach-o/loader.h"
29
30 static void
31 obj_mach_o_weak (int ignore ATTRIBUTE_UNUSED)
32 {
33   char *name;
34   int c;
35   symbolS *symbolP;
36
37   do
38     {
39       /* Get symbol name.  */
40       name = input_line_pointer;
41       c = get_symbol_end ();
42       symbolP = symbol_find_or_make (name);
43       S_SET_WEAK (symbolP);
44       *input_line_pointer = c;
45       SKIP_WHITESPACE ();
46
47       if (c != ',')
48         break;
49       input_line_pointer++;
50       SKIP_WHITESPACE ();
51     }
52   while (*input_line_pointer != '\n');
53   demand_empty_rest_of_line ();
54 }
55
56 /* Parse:
57    .section segname,sectname[,type[,attribute[,sizeof_stub]]]
58 */
59
60 static void
61 obj_mach_o_section (int ignore ATTRIBUTE_UNUSED)
62 {
63   char *p;
64   char *segname;
65   char *sectname;
66   char c;
67   int sectype = BFD_MACH_O_S_REGULAR;
68   unsigned int secattr = 0;
69   offsetT sizeof_stub = 0;
70   const char *name;
71   flagword oldflags, flags;
72   asection *sec;
73
74   /* Parse segment name.  */
75   if (!is_name_beginner (*input_line_pointer))
76     {
77       as_bad (_("missing segment name"));
78       ignore_rest_of_line ();
79       return;
80     }
81   p = input_line_pointer;
82   c = get_symbol_end ();
83   segname = alloca (input_line_pointer - p + 1);
84   strcpy (segname, p);
85   *input_line_pointer = c;
86
87   if (*input_line_pointer != ',')
88     {
89       as_bad (_("missing comma after segment name"));
90       ignore_rest_of_line ();
91       return;
92     }
93   input_line_pointer++;
94
95   /* Parse section name.  */
96   if (!is_name_beginner (*input_line_pointer))
97     {
98       as_bad (_("missing section name"));
99       ignore_rest_of_line ();
100       return;
101     }
102   p = input_line_pointer;
103   c = get_symbol_end ();
104   sectname = alloca (input_line_pointer - p + 1);
105   strcpy (sectname, p);
106   *input_line_pointer = c;
107
108   /* Parse type.  */
109   if (*input_line_pointer == ',')
110     {
111       input_line_pointer++;
112       if (!is_name_beginner (*input_line_pointer))
113         {
114           as_bad (_("missing section type name"));
115           ignore_rest_of_line ();
116           return;
117         }
118       p = input_line_pointer;
119       c = get_symbol_end ();
120
121       sectype = bfd_mach_o_get_section_type_from_name (p);
122       if (sectype == -1)
123         {
124           as_bad (_("unknown or invalid section type '%s'"), p);
125           sectype = BFD_MACH_O_S_REGULAR;
126         }
127       *input_line_pointer = c;
128
129       /* Parse attributes.  */
130       if (*input_line_pointer == ',')
131         {
132           do
133             {
134               int attr;
135
136               input_line_pointer++;
137
138               if (!is_name_beginner (*input_line_pointer))
139                 {
140                   as_bad (_("missing section attribute identifier"));
141                   ignore_rest_of_line ();
142                   break;
143                 }
144               p = input_line_pointer;
145               c = get_symbol_end ();
146
147               attr = bfd_mach_o_get_section_attribute_from_name (p);
148               if (attr == -1)
149                 as_bad (_("unknown or invalid section attribute '%s'"), p);
150               else
151                 secattr |= attr;
152
153               *input_line_pointer = c;
154             }
155           while (*input_line_pointer == '+');
156
157           /* Parse sizeof_stub.  */
158           if (*input_line_pointer == ',')
159             {
160               if (sectype != BFD_MACH_O_S_SYMBOL_STUBS)
161                 as_bad (_("unexpected sizeof_stub expression"));
162
163               sizeof_stub = get_absolute_expression ();
164             }
165           else if (sectype == BFD_MACH_O_S_SYMBOL_STUBS)
166             as_bad (_("missing sizeof_stub expression"));
167         }
168     }
169   demand_empty_rest_of_line ();
170
171   bfd_mach_o_normalize_section_name (segname, sectname, &name, &flags);
172   if (name == NULL)
173     {
174       /* There is no normal BFD section name for this section.  Create one.
175          The name created doesn't really matter as it will never be written
176          on disk.  */
177       size_t seglen = strlen (segname);
178       size_t sectlen = strlen (sectname);
179       char *n;
180
181       n = xmalloc (seglen + 1 + sectlen + 1);
182       memcpy (n, segname, seglen);
183       n[seglen] = '.';
184       memcpy (n + seglen + 1, sectname, sectlen);
185       n[seglen + 1 + sectlen] = 0;
186       name = n;
187     }
188
189 #ifdef md_flush_pending_output
190   md_flush_pending_output ();
191 #endif
192
193   /* Sub-segments don't exists as is on Mach-O.  */
194   sec = subseg_new (name, 0);
195
196   oldflags = bfd_get_section_flags (stdoutput, sec);
197   if (oldflags == SEC_NO_FLAGS)
198     {
199       bfd_mach_o_section *msect;
200
201       if (! bfd_set_section_flags (stdoutput, sec, flags))
202         as_warn (_("error setting flags for \"%s\": %s"),
203                  bfd_section_name (stdoutput, sec),
204                  bfd_errmsg (bfd_get_error ()));
205       msect = bfd_mach_o_get_mach_o_section (sec);
206       strncpy (msect->segname, segname, sizeof (msect->segname));
207       msect->segname[16] = 0;
208       strncpy (msect->sectname, sectname, sizeof (msect->sectname));
209       msect->sectname[16] = 0;
210       msect->flags = secattr | sectype;
211       msect->reserved2 = sizeof_stub;
212     }
213   else if (flags != SEC_NO_FLAGS)
214     {
215       if (flags != oldflags)
216         as_warn (_("Ignoring changed section attributes for %s"), name);
217     }
218 }
219
220 struct known_section
221 {
222   const char *name;
223   unsigned int flags;
224 };
225
226 static const struct known_section known_sections[] =
227   {
228     /* 0 */ { NULL, 0},
229     /* 1 */ { ".cstring", BFD_MACH_O_S_CSTRING_LITERALS }
230   };
231
232 static void
233 obj_mach_o_known_section (int sect_index)
234 {
235   const struct known_section *sect = &known_sections[sect_index];
236   asection *old_sec;
237   segT sec;
238
239 #ifdef md_flush_pending_output
240   md_flush_pending_output ();
241 #endif
242
243   old_sec = bfd_get_section_by_name (stdoutput, sect->name);
244   if (old_sec)
245     {
246       /* Section already present.  */
247       sec = old_sec;
248       subseg_set (sec, 0);
249     }
250   else
251     {
252       bfd_mach_o_section *msect;
253
254       sec = subseg_force_new (sect->name, 0);
255
256       /* Set default flags.  */
257       msect = bfd_mach_o_get_mach_o_section (sec);
258       msect->flags = sect->flags;
259     }
260 }
261
262 /* Called from read.c:s_comm after we've parsed .comm symbol, size.
263    Parse a possible alignment value.  */
264
265 static symbolS *
266 obj_mach_o_common_parse (int ignore ATTRIBUTE_UNUSED,
267                          symbolS *symbolP, addressT size)
268 {
269   addressT align = 0;
270
271   if (*input_line_pointer == ',')
272     {
273       align = parse_align (0);
274       if (align == (addressT) -1)
275         return NULL;
276     }
277
278   S_SET_VALUE (symbolP, size);
279   S_SET_EXTERNAL (symbolP);
280   S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
281
282   symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
283
284   return symbolP;
285 }
286
287 static void
288 obj_mach_o_comm (int ignore ATTRIBUTE_UNUSED)
289 {
290   s_comm_internal (ignore, obj_mach_o_common_parse);
291 }
292
293 static void
294 obj_mach_o_subsections_via_symbols (int arg ATTRIBUTE_UNUSED)
295 {
296   /* Currently ignore it.  */
297   demand_empty_rest_of_line ();
298 }
299
300 const pseudo_typeS mach_o_pseudo_table[] =
301 {
302   { "weak", obj_mach_o_weak, 0},
303   { "section", obj_mach_o_section, 0},
304   { "cstring", obj_mach_o_known_section, 1},
305   { "lcomm", s_lcomm, 1 },
306   { "comm", obj_mach_o_comm, 0 },
307   { "subsections_via_symbols", obj_mach_o_subsections_via_symbols, 0 },
308
309   {NULL, NULL, 0}
310 };