Commit | Line | Data |
---|---|---|
e57f8c65 TG |
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" | |
74a6005f TG |
24 | #include "subsegs.h" |
25 | #include "symbols.h" | |
26 | #include "write.h" | |
e57f8c65 | 27 | #include "mach-o.h" |
74a6005f | 28 | #include "mach-o/loader.h" |
e57f8c65 TG |
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 | ||
74a6005f TG |
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 | ||
e57f8c65 TG |
300 | const pseudo_typeS mach_o_pseudo_table[] = |
301 | { | |
74a6005f TG |
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 }, | |
e57f8c65 TG |
308 | |
309 | {NULL, NULL, 0} | |
310 | }; |