simple-object-mach-o.c revision 1.1.1.4 1 1.1 christos /* simple-object-mach-o.c -- routines to manipulate Mach-O object files.
2 1.1.1.4 christos Copyright (C) 2010-2020 Free Software Foundation, Inc.
3 1.1 christos Written by Ian Lance Taylor, Google.
4 1.1 christos
5 1.1 christos This program is free software; you can redistribute it and/or modify it
6 1.1 christos under the terms of the GNU General Public License as published by the
7 1.1 christos Free Software Foundation; either version 2, or (at your option) any
8 1.1 christos later version.
9 1.1 christos
10 1.1 christos This program is distributed in the hope that it will be useful,
11 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 1.1 christos GNU General Public License for more details.
14 1.1 christos
15 1.1 christos You should have received a copy of the GNU General Public License
16 1.1 christos along with this program; if not, write to the Free Software
17 1.1 christos Foundation, 51 Franklin Street - Fifth Floor,
18 1.1 christos Boston, MA 02110-1301, USA. */
19 1.1 christos
20 1.1 christos #include "config.h"
21 1.1 christos #include "libiberty.h"
22 1.1 christos #include "simple-object.h"
23 1.1 christos
24 1.1 christos #include <stddef.h>
25 1.1 christos
26 1.1 christos #ifdef HAVE_STDLIB_H
27 1.1 christos #include <stdlib.h>
28 1.1 christos #endif
29 1.1 christos
30 1.1 christos #ifdef HAVE_STDINT_H
31 1.1 christos #include <stdint.h>
32 1.1 christos #endif
33 1.1 christos
34 1.1 christos #ifdef HAVE_STRING_H
35 1.1 christos #include <string.h>
36 1.1 christos #endif
37 1.1 christos
38 1.1 christos #ifdef HAVE_INTTYPES_H
39 1.1 christos #include <inttypes.h>
40 1.1 christos #endif
41 1.1 christos
42 1.1 christos #include "simple-object-common.h"
43 1.1 christos
44 1.1 christos /* Mach-O structures and constants. */
45 1.1 christos
46 1.1 christos /* Mach-O header (32-bit version). */
47 1.1 christos
48 1.1 christos struct mach_o_header_32
49 1.1 christos {
50 1.1 christos unsigned char magic[4]; /* Magic number. */
51 1.1 christos unsigned char cputype[4]; /* CPU that this object is for. */
52 1.1 christos unsigned char cpusubtype[4]; /* CPU subtype. */
53 1.1 christos unsigned char filetype[4]; /* Type of file. */
54 1.1 christos unsigned char ncmds[4]; /* Number of load commands. */
55 1.1 christos unsigned char sizeofcmds[4]; /* Total size of load commands. */
56 1.1 christos unsigned char flags[4]; /* Flags for special featues. */
57 1.1 christos };
58 1.1 christos
59 1.1 christos /* Mach-O header (64-bit version). */
60 1.1 christos
61 1.1 christos struct mach_o_header_64
62 1.1 christos {
63 1.1 christos unsigned char magic[4]; /* Magic number. */
64 1.1 christos unsigned char cputype[4]; /* CPU that this object is for. */
65 1.1 christos unsigned char cpusubtype[4]; /* CPU subtype. */
66 1.1 christos unsigned char filetype[4]; /* Type of file. */
67 1.1 christos unsigned char ncmds[4]; /* Number of load commands. */
68 1.1 christos unsigned char sizeofcmds[4]; /* Total size of load commands. */
69 1.1 christos unsigned char flags[4]; /* Flags for special featues. */
70 1.1 christos unsigned char reserved[4]; /* Reserved. Duh. */
71 1.1 christos };
72 1.1 christos
73 1.1 christos /* For magic field in header. */
74 1.1 christos
75 1.1 christos #define MACH_O_MH_MAGIC 0xfeedface
76 1.1 christos #define MACH_O_MH_MAGIC_64 0xfeedfacf
77 1.1 christos
78 1.1 christos /* For filetype field in header. */
79 1.1 christos
80 1.1 christos #define MACH_O_MH_OBJECT 0x01
81 1.1 christos
82 1.1 christos /* A Mach-O file is a list of load commands. This is the header of a
83 1.1 christos load command. */
84 1.1 christos
85 1.1 christos struct mach_o_load_command
86 1.1 christos {
87 1.1 christos unsigned char cmd[4]; /* The type of load command. */
88 1.1 christos unsigned char cmdsize[4]; /* Size in bytes of entire command. */
89 1.1 christos };
90 1.1 christos
91 1.1 christos /* For cmd field in load command. */
92 1.1 christos
93 1.1 christos #define MACH_O_LC_SEGMENT 0x01
94 1.1 christos #define MACH_O_LC_SEGMENT_64 0x19
95 1.1 christos
96 1.1 christos /* LC_SEGMENT load command. */
97 1.1 christos
98 1.1 christos struct mach_o_segment_command_32
99 1.1 christos {
100 1.1 christos unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */
101 1.1 christos unsigned char cmdsize[4]; /* Size in bytes of entire command. */
102 1.1 christos unsigned char segname[16]; /* Name of this segment. */
103 1.1 christos unsigned char vmaddr[4]; /* Virtual memory address of this segment. */
104 1.1 christos unsigned char vmsize[4]; /* Size there, in bytes. */
105 1.1 christos unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */
106 1.1 christos unsigned char filesize[4]; /* Size in bytes on disk. */
107 1.1 christos unsigned char maxprot[4]; /* Maximum permitted vmem protection. */
108 1.1 christos unsigned char initprot[4]; /* Initial vmem protection. */
109 1.1 christos unsigned char nsects[4]; /* Number of sections in this segment. */
110 1.1 christos unsigned char flags[4]; /* Flags that affect the loading. */
111 1.1 christos };
112 1.1 christos
113 1.1 christos /* LC_SEGMENT_64 load command. */
114 1.1 christos
115 1.1 christos struct mach_o_segment_command_64
116 1.1 christos {
117 1.1 christos unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */
118 1.1 christos unsigned char cmdsize[4]; /* Size in bytes of entire command. */
119 1.1 christos unsigned char segname[16]; /* Name of this segment. */
120 1.1 christos unsigned char vmaddr[8]; /* Virtual memory address of this segment. */
121 1.1 christos unsigned char vmsize[8]; /* Size there, in bytes. */
122 1.1 christos unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */
123 1.1 christos unsigned char filesize[8]; /* Size in bytes on disk. */
124 1.1 christos unsigned char maxprot[4]; /* Maximum permitted vmem protection. */
125 1.1 christos unsigned char initprot[4]; /* Initial vmem protection. */
126 1.1 christos unsigned char nsects[4]; /* Number of sections in this segment. */
127 1.1 christos unsigned char flags[4]; /* Flags that affect the loading. */
128 1.1 christos };
129 1.1 christos
130 1.1 christos /* 32-bit section header. */
131 1.1 christos
132 1.1 christos struct mach_o_section_32
133 1.1 christos {
134 1.1 christos unsigned char sectname[16]; /* Section name. */
135 1.1 christos unsigned char segname[16]; /* Segment that the section belongs to. */
136 1.1 christos unsigned char addr[4]; /* Address of this section in memory. */
137 1.1 christos unsigned char size[4]; /* Size in bytes of this section. */
138 1.1 christos unsigned char offset[4]; /* File offset of this section. */
139 1.1 christos unsigned char align[4]; /* log2 of this section's alignment. */
140 1.1 christos unsigned char reloff[4]; /* File offset of this section's relocs. */
141 1.1 christos unsigned char nreloc[4]; /* Number of relocs for this section. */
142 1.1 christos unsigned char flags[4]; /* Section flags/attributes. */
143 1.1 christos unsigned char reserved1[4];
144 1.1 christos unsigned char reserved2[4];
145 1.1 christos };
146 1.1 christos
147 1.1 christos /* 64-bit section header. */
148 1.1 christos
149 1.1 christos struct mach_o_section_64
150 1.1 christos {
151 1.1 christos unsigned char sectname[16]; /* Section name. */
152 1.1 christos unsigned char segname[16]; /* Segment that the section belongs to. */
153 1.1 christos unsigned char addr[8]; /* Address of this section in memory. */
154 1.1 christos unsigned char size[8]; /* Size in bytes of this section. */
155 1.1 christos unsigned char offset[4]; /* File offset of this section. */
156 1.1 christos unsigned char align[4]; /* log2 of this section's alignment. */
157 1.1 christos unsigned char reloff[4]; /* File offset of this section's relocs. */
158 1.1 christos unsigned char nreloc[4]; /* Number of relocs for this section. */
159 1.1 christos unsigned char flags[4]; /* Section flags/attributes. */
160 1.1 christos unsigned char reserved1[4];
161 1.1 christos unsigned char reserved2[4];
162 1.1 christos unsigned char reserved3[4];
163 1.1 christos };
164 1.1 christos
165 1.1 christos /* Flags for Mach-O sections. */
166 1.1 christos
167 1.1 christos #define MACH_O_S_ATTR_DEBUG 0x02000000
168 1.1 christos
169 1.1 christos /* The length of a segment or section name. */
170 1.1 christos
171 1.1 christos #define MACH_O_NAME_LEN (16)
172 1.1 christos
173 1.1 christos /* A GNU specific extension for long section names. */
174 1.1 christos
175 1.1 christos #define GNU_SECTION_NAMES "__section_names"
176 1.1 christos
177 1.1 christos /* A GNU-specific extension to wrap multiple sections using three
178 1.1 christos mach-o sections within a given segment. The section '__wrapper_sects'
179 1.1 christos is subdivided according to the index '__wrapper_index' and each sub
180 1.1 christos sect is named according to the names supplied in '__wrapper_names'. */
181 1.1 christos
182 1.1 christos #define GNU_WRAPPER_SECTS "__wrapper_sects"
183 1.1 christos #define GNU_WRAPPER_INDEX "__wrapper_index"
184 1.1 christos #define GNU_WRAPPER_NAMES "__wrapper_names"
185 1.1 christos
186 1.1 christos /* Private data for an simple_object_read. */
187 1.1 christos
188 1.1 christos struct simple_object_mach_o_read
189 1.1 christos {
190 1.1 christos /* User specified segment name. */
191 1.1 christos char *segment_name;
192 1.1 christos /* Magic number. */
193 1.1 christos unsigned int magic;
194 1.1 christos /* Whether this file is big-endian. */
195 1.1 christos int is_big_endian;
196 1.1 christos /* CPU type from header. */
197 1.1 christos unsigned int cputype;
198 1.1 christos /* CPU subtype from header. */
199 1.1 christos unsigned int cpusubtype;
200 1.1 christos /* Number of commands, from header. */
201 1.1 christos unsigned int ncmds;
202 1.1 christos /* Flags from header. */
203 1.1 christos unsigned int flags;
204 1.1 christos /* Reserved field from header, only used on 64-bit. */
205 1.1 christos unsigned int reserved;
206 1.1 christos };
207 1.1 christos
208 1.1 christos /* Private data for an simple_object_attributes. */
209 1.1 christos
210 1.1 christos struct simple_object_mach_o_attributes
211 1.1 christos {
212 1.1 christos /* Magic number. */
213 1.1 christos unsigned int magic;
214 1.1 christos /* Whether this file is big-endian. */
215 1.1 christos int is_big_endian;
216 1.1 christos /* CPU type from header. */
217 1.1 christos unsigned int cputype;
218 1.1 christos /* CPU subtype from header. */
219 1.1 christos unsigned int cpusubtype;
220 1.1 christos /* Flags from header. */
221 1.1 christos unsigned int flags;
222 1.1 christos /* Reserved field from header, only used on 64-bit. */
223 1.1 christos unsigned int reserved;
224 1.1 christos };
225 1.1 christos
226 1.1 christos /* See if we have a Mach-O MH_OBJECT file:
227 1.1 christos
228 1.1 christos A standard MH_OBJECT (from as) will have three load commands:
229 1.1 christos 0 - LC_SEGMENT/LC_SEGMENT64
230 1.1 christos 1 - LC_SYMTAB
231 1.1 christos 2 - LC_DYSYMTAB
232 1.1 christos
233 1.1 christos The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment
234 1.1 christos containing all the sections.
235 1.1 christos
236 1.1 christos Files written by simple-object will have only the segment command
237 1.1 christos (no symbol tables). */
238 1.1 christos
239 1.1 christos static void *
240 1.1 christos simple_object_mach_o_match (
241 1.1 christos unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN],
242 1.1 christos int descriptor,
243 1.1 christos off_t offset,
244 1.1 christos const char *segment_name,
245 1.1 christos const char **errmsg,
246 1.1 christos int *err)
247 1.1 christos {
248 1.1 christos unsigned int magic;
249 1.1 christos int is_big_endian;
250 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
251 1.1 christos unsigned int filetype;
252 1.1 christos struct simple_object_mach_o_read *omr;
253 1.1 christos unsigned char buf[sizeof (struct mach_o_header_64)];
254 1.1 christos unsigned char *b;
255 1.1 christos
256 1.1 christos magic = simple_object_fetch_big_32 (header);
257 1.1 christos if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
258 1.1 christos is_big_endian = 1;
259 1.1 christos else
260 1.1 christos {
261 1.1 christos magic = simple_object_fetch_little_32 (header);
262 1.1 christos if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64)
263 1.1 christos is_big_endian = 0;
264 1.1 christos else
265 1.1 christos {
266 1.1 christos *errmsg = NULL;
267 1.1 christos *err = 0;
268 1.1 christos return NULL;
269 1.1 christos }
270 1.1 christos }
271 1.1 christos
272 1.1 christos #ifndef UNSIGNED_64BIT_TYPE
273 1.1 christos if (magic == MACH_O_MH_MAGIC_64)
274 1.1 christos {
275 1.1 christos *errmsg = "64-bit Mach-O objects not supported";
276 1.1 christos *err = 0;
277 1.1 christos return NULL;
278 1.1 christos }
279 1.1 christos #endif
280 1.1 christos
281 1.1 christos /* We require the user to provide a segment name. This is
282 1.1 christos unfortunate but I don't see any good choices here. */
283 1.1 christos
284 1.1 christos if (segment_name == NULL)
285 1.1 christos {
286 1.1 christos *errmsg = "Mach-O file found but no segment name specified";
287 1.1 christos *err = 0;
288 1.1 christos return NULL;
289 1.1 christos }
290 1.1 christos
291 1.1 christos if (strlen (segment_name) > MACH_O_NAME_LEN)
292 1.1 christos {
293 1.1 christos *errmsg = "Mach-O segment name too long";
294 1.1 christos *err = 0;
295 1.1 christos return NULL;
296 1.1 christos }
297 1.1 christos
298 1.1 christos /* The 32-bit and 64-bit headers are similar enough that we can use
299 1.1 christos the same code. */
300 1.1 christos
301 1.1 christos fetch_32 = (is_big_endian
302 1.1 christos ? simple_object_fetch_big_32
303 1.1 christos : simple_object_fetch_little_32);
304 1.1 christos
305 1.1 christos if (!simple_object_internal_read (descriptor, offset, buf,
306 1.1 christos (magic == MACH_O_MH_MAGIC
307 1.1 christos ? sizeof (struct mach_o_header_32)
308 1.1 christos : sizeof (struct mach_o_header_64)),
309 1.1 christos errmsg, err))
310 1.1 christos return NULL;
311 1.1 christos
312 1.1 christos b = &buf[0];
313 1.1 christos
314 1.1 christos filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype));
315 1.1 christos if (filetype != MACH_O_MH_OBJECT)
316 1.1 christos {
317 1.1 christos *errmsg = "Mach-O file is not object file";
318 1.1 christos *err = 0;
319 1.1 christos return NULL;
320 1.1 christos }
321 1.1 christos
322 1.1 christos omr = XNEW (struct simple_object_mach_o_read);
323 1.1 christos omr->segment_name = xstrdup (segment_name);
324 1.1 christos omr->magic = magic;
325 1.1 christos omr->is_big_endian = is_big_endian;
326 1.1 christos omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype));
327 1.1 christos omr->cpusubtype = (*fetch_32) (b
328 1.1 christos + offsetof (struct mach_o_header_32,
329 1.1 christos cpusubtype));
330 1.1 christos omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds));
331 1.1 christos omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags));
332 1.1 christos if (magic == MACH_O_MH_MAGIC)
333 1.1 christos omr->reserved = 0;
334 1.1 christos else
335 1.1 christos omr->reserved = (*fetch_32) (b
336 1.1 christos + offsetof (struct mach_o_header_64,
337 1.1 christos reserved));
338 1.1 christos
339 1.1 christos return (void *) omr;
340 1.1 christos }
341 1.1 christos
342 1.1 christos /* Get the file offset and size from a section header. */
343 1.1 christos
344 1.1 christos static void
345 1.1 christos simple_object_mach_o_section_info (int is_big_endian, int is_32,
346 1.1 christos const unsigned char *sechdr, off_t *offset,
347 1.1 christos size_t *size)
348 1.1 christos {
349 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
350 1.1 christos ulong_type (*fetch_64) (const unsigned char *);
351 1.1 christos
352 1.1 christos fetch_32 = (is_big_endian
353 1.1 christos ? simple_object_fetch_big_32
354 1.1 christos : simple_object_fetch_little_32);
355 1.1 christos
356 1.1 christos fetch_64 = NULL;
357 1.1 christos #ifdef UNSIGNED_64BIT_TYPE
358 1.1 christos fetch_64 = (is_big_endian
359 1.1 christos ? simple_object_fetch_big_64
360 1.1 christos : simple_object_fetch_little_64);
361 1.1 christos #endif
362 1.1 christos
363 1.1 christos if (is_32)
364 1.1 christos {
365 1.1 christos *offset = fetch_32 (sechdr
366 1.1 christos + offsetof (struct mach_o_section_32, offset));
367 1.1 christos *size = fetch_32 (sechdr
368 1.1 christos + offsetof (struct mach_o_section_32, size));
369 1.1 christos }
370 1.1 christos else
371 1.1 christos {
372 1.1 christos *offset = fetch_32 (sechdr
373 1.1 christos + offsetof (struct mach_o_section_64, offset));
374 1.1 christos *size = fetch_64 (sechdr
375 1.1 christos + offsetof (struct mach_o_section_64, size));
376 1.1 christos }
377 1.1 christos }
378 1.1 christos
379 1.1 christos /* Handle a segment in a Mach-O Object file.
380 1.1 christos
381 1.1 christos This will callback to the function pfn for each "section found" the meaning
382 1.1 christos of which depends on gnu extensions to mach-o:
383 1.1 christos
384 1.1 christos If we find mach-o sections (with the segment name as specified) which also
385 1.1 christos contain: a 'sects' wrapper, an index, and a name table, we expand this into
386 1.1 christos as many sections as are specified in the index. In this case, there will
387 1.1 christos be a callback for each of these.
388 1.1 christos
389 1.1 christos We will also allow an extension that permits long names (more than 16
390 1.1 christos characters) to be used with mach-o. In this case, the section name has
391 1.1 christos a specific format embedding an index into a name table, and the file must
392 1.1 christos contain such name table.
393 1.1 christos
394 1.1 christos Return 1 if we should continue, 0 if the caller should return. */
395 1.1 christos
396 1.1 christos #define SOMO_SECTS_PRESENT 0x01
397 1.1 christos #define SOMO_INDEX_PRESENT 0x02
398 1.1 christos #define SOMO_NAMES_PRESENT 0x04
399 1.1 christos #define SOMO_LONGN_PRESENT 0x08
400 1.1 christos #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \
401 1.1 christos | SOMO_NAMES_PRESENT)
402 1.1 christos
403 1.1 christos static int
404 1.1 christos simple_object_mach_o_segment (simple_object_read *sobj, off_t offset,
405 1.1 christos const unsigned char *segbuf,
406 1.1 christos int (*pfn) (void *, const char *, off_t offset,
407 1.1 christos off_t length),
408 1.1 christos void *data,
409 1.1 christos const char **errmsg, int *err)
410 1.1 christos {
411 1.1 christos struct simple_object_mach_o_read *omr =
412 1.1 christos (struct simple_object_mach_o_read *) sobj->data;
413 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
414 1.1 christos int is_32;
415 1.1 christos size_t seghdrsize;
416 1.1 christos size_t sechdrsize;
417 1.1 christos size_t segname_offset;
418 1.1 christos size_t sectname_offset;
419 1.1 christos unsigned int nsects;
420 1.1 christos unsigned char *secdata;
421 1.1 christos unsigned int i;
422 1.1 christos unsigned int gnu_sections_found;
423 1.1 christos unsigned int strtab_index;
424 1.1 christos unsigned int index_index;
425 1.1 christos unsigned int nametab_index;
426 1.1 christos unsigned int sections_index;
427 1.1 christos char *strtab;
428 1.1 christos char *nametab;
429 1.1 christos unsigned char *index;
430 1.1 christos size_t strtab_size;
431 1.1 christos size_t nametab_size;
432 1.1 christos size_t index_size;
433 1.1 christos unsigned int n_wrapped_sects;
434 1.1 christos size_t wrapper_sect_size;
435 1.1 christos off_t wrapper_sect_offset = 0;
436 1.1 christos
437 1.1 christos fetch_32 = (omr->is_big_endian
438 1.1 christos ? simple_object_fetch_big_32
439 1.1 christos : simple_object_fetch_little_32);
440 1.1 christos
441 1.1 christos is_32 = omr->magic == MACH_O_MH_MAGIC;
442 1.1 christos
443 1.1 christos if (is_32)
444 1.1 christos {
445 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_32);
446 1.1 christos sechdrsize = sizeof (struct mach_o_section_32);
447 1.1 christos segname_offset = offsetof (struct mach_o_section_32, segname);
448 1.1 christos sectname_offset = offsetof (struct mach_o_section_32, sectname);
449 1.1 christos nsects = (*fetch_32) (segbuf
450 1.1 christos + offsetof (struct mach_o_segment_command_32,
451 1.1 christos nsects));
452 1.1 christos }
453 1.1 christos else
454 1.1 christos {
455 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_64);
456 1.1 christos sechdrsize = sizeof (struct mach_o_section_64);
457 1.1 christos segname_offset = offsetof (struct mach_o_section_64, segname);
458 1.1 christos sectname_offset = offsetof (struct mach_o_section_64, sectname);
459 1.1 christos nsects = (*fetch_32) (segbuf
460 1.1 christos + offsetof (struct mach_o_segment_command_64,
461 1.1 christos nsects));
462 1.1 christos }
463 1.1 christos
464 1.1 christos /* Fetch the section headers from the segment command. */
465 1.1 christos
466 1.1 christos secdata = XNEWVEC (unsigned char, nsects * sechdrsize);
467 1.1 christos if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize,
468 1.1 christos secdata, nsects * sechdrsize, errmsg, err))
469 1.1 christos {
470 1.1 christos XDELETEVEC (secdata);
471 1.1 christos return 0;
472 1.1 christos }
473 1.1 christos
474 1.1 christos /* Scan for special sections that signal GNU extensions to the format. */
475 1.1 christos
476 1.1 christos gnu_sections_found = 0;
477 1.1 christos index_index = nsects;
478 1.1 christos sections_index = nsects;
479 1.1 christos strtab_index = nsects;
480 1.1 christos nametab_index = nsects;
481 1.1 christos for (i = 0; i < nsects; ++i)
482 1.1 christos {
483 1.1 christos size_t nameoff;
484 1.1 christos
485 1.1 christos nameoff = i * sechdrsize + segname_offset;
486 1.1 christos if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0)
487 1.1 christos continue;
488 1.1 christos
489 1.1 christos nameoff = i * sechdrsize + sectname_offset;
490 1.1 christos if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0)
491 1.1 christos {
492 1.1 christos nametab_index = i;
493 1.1 christos gnu_sections_found |= SOMO_NAMES_PRESENT;
494 1.1 christos }
495 1.1 christos else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0)
496 1.1 christos {
497 1.1 christos index_index = i;
498 1.1 christos gnu_sections_found |= SOMO_INDEX_PRESENT;
499 1.1 christos }
500 1.1 christos else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0)
501 1.1 christos {
502 1.1 christos sections_index = i;
503 1.1 christos gnu_sections_found |= SOMO_SECTS_PRESENT;
504 1.1 christos }
505 1.1 christos else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0)
506 1.1 christos {
507 1.1 christos strtab_index = i;
508 1.1 christos gnu_sections_found |= SOMO_LONGN_PRESENT;
509 1.1 christos }
510 1.1 christos }
511 1.1 christos
512 1.1 christos /* If any of the special wrapper section components is present, then
513 1.1 christos they all should be. */
514 1.1 christos
515 1.1 christos if ((gnu_sections_found & SOMO_WRAPPING) != 0)
516 1.1 christos {
517 1.1 christos off_t nametab_offset;
518 1.1 christos off_t index_offset;
519 1.1 christos
520 1.1 christos if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING)
521 1.1 christos {
522 1.1 christos *errmsg = "GNU Mach-o section wrapper: required section missing";
523 1.1 christos *err = 0; /* No useful errno. */
524 1.1 christos XDELETEVEC (secdata);
525 1.1 christos return 0;
526 1.1 christos }
527 1.1 christos
528 1.1 christos /* Fetch the name table. */
529 1.1 christos
530 1.1 christos simple_object_mach_o_section_info (omr->is_big_endian, is_32,
531 1.1 christos secdata + nametab_index * sechdrsize,
532 1.1 christos &nametab_offset, &nametab_size);
533 1.1 christos nametab = XNEWVEC (char, nametab_size);
534 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
535 1.1 christos sobj->offset + nametab_offset,
536 1.1 christos (unsigned char *) nametab, nametab_size,
537 1.1 christos errmsg, err))
538 1.1 christos {
539 1.1 christos XDELETEVEC (nametab);
540 1.1 christos XDELETEVEC (secdata);
541 1.1 christos return 0;
542 1.1 christos }
543 1.1 christos
544 1.1 christos /* Fetch the index. */
545 1.1 christos
546 1.1 christos simple_object_mach_o_section_info (omr->is_big_endian, is_32,
547 1.1 christos secdata + index_index * sechdrsize,
548 1.1 christos &index_offset, &index_size);
549 1.1 christos index = XNEWVEC (unsigned char, index_size);
550 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
551 1.1 christos sobj->offset + index_offset,
552 1.1 christos index, index_size,
553 1.1 christos errmsg, err))
554 1.1 christos {
555 1.1 christos XDELETEVEC (index);
556 1.1 christos XDELETEVEC (nametab);
557 1.1 christos XDELETEVEC (secdata);
558 1.1 christos return 0;
559 1.1 christos }
560 1.1 christos
561 1.1 christos /* The index contains 4 unsigned ints per sub-section:
562 1.1 christos sub-section offset/length, sub-section name/length.
563 1.1 christos We fix this for both 32 and 64 bit mach-o for now, since
564 1.1 christos other fields limit the maximum size of an object to 4G. */
565 1.1 christos n_wrapped_sects = index_size / 16;
566 1.1 christos
567 1.1 christos /* Get the parameters for the wrapper too. */
568 1.1 christos simple_object_mach_o_section_info (omr->is_big_endian, is_32,
569 1.1 christos secdata + sections_index * sechdrsize,
570 1.1 christos &wrapper_sect_offset,
571 1.1 christos &wrapper_sect_size);
572 1.1 christos }
573 1.1 christos else
574 1.1 christos {
575 1.1 christos index = NULL;
576 1.1 christos index_size = 0;
577 1.1 christos nametab = NULL;
578 1.1 christos nametab_size = 0;
579 1.1 christos n_wrapped_sects = 0;
580 1.1 christos }
581 1.1 christos
582 1.1 christos /* If we have a long names section, fetch it. */
583 1.1 christos
584 1.1 christos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
585 1.1 christos {
586 1.1 christos off_t strtab_offset;
587 1.1 christos
588 1.1 christos simple_object_mach_o_section_info (omr->is_big_endian, is_32,
589 1.1 christos secdata + strtab_index * sechdrsize,
590 1.1 christos &strtab_offset, &strtab_size);
591 1.1 christos strtab = XNEWVEC (char, strtab_size);
592 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
593 1.1 christos sobj->offset + strtab_offset,
594 1.1 christos (unsigned char *) strtab, strtab_size,
595 1.1 christos errmsg, err))
596 1.1 christos {
597 1.1 christos XDELETEVEC (strtab);
598 1.1 christos XDELETEVEC (index);
599 1.1 christos XDELETEVEC (nametab);
600 1.1 christos XDELETEVEC (secdata);
601 1.1 christos return 0;
602 1.1 christos }
603 1.1 christos }
604 1.1 christos else
605 1.1 christos {
606 1.1 christos strtab = NULL;
607 1.1 christos strtab_size = 0;
608 1.1 christos strtab_index = nsects;
609 1.1 christos }
610 1.1 christos
611 1.1 christos /* Process the sections. */
612 1.1 christos
613 1.1 christos for (i = 0; i < nsects; ++i)
614 1.1 christos {
615 1.1 christos const unsigned char *sechdr;
616 1.1 christos char namebuf[MACH_O_NAME_LEN * 2 + 2];
617 1.1 christos char *name;
618 1.1 christos off_t secoffset;
619 1.1 christos size_t secsize;
620 1.1 christos int l;
621 1.1 christos
622 1.1 christos sechdr = secdata + i * sechdrsize;
623 1.1 christos
624 1.1 christos /* We've already processed the long section names. */
625 1.1 christos
626 1.1 christos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0
627 1.1 christos && i == strtab_index)
628 1.1 christos continue;
629 1.1 christos
630 1.1 christos /* We only act on the segment named. */
631 1.1 christos
632 1.1 christos if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0)
633 1.1 christos continue;
634 1.1 christos
635 1.1 christos /* Process sections associated with the wrapper. */
636 1.1 christos
637 1.1 christos if ((gnu_sections_found & SOMO_WRAPPING) != 0)
638 1.1 christos {
639 1.1 christos if (i == nametab_index || i == index_index)
640 1.1 christos continue;
641 1.1 christos
642 1.1 christos if (i == sections_index)
643 1.1 christos {
644 1.1 christos unsigned int j;
645 1.1 christos for (j = 0; j < n_wrapped_sects; ++j)
646 1.1 christos {
647 1.1 christos unsigned int subsect_offset, subsect_length, name_offset;
648 1.1 christos subsect_offset = (*fetch_32) (index + 16 * j);
649 1.1 christos subsect_length = (*fetch_32) (index + 16 * j + 4);
650 1.1 christos name_offset = (*fetch_32) (index + 16 * j + 8);
651 1.1 christos /* We don't need the name_length yet. */
652 1.1 christos
653 1.1 christos secoffset = wrapper_sect_offset + subsect_offset;
654 1.1 christos secsize = subsect_length;
655 1.1 christos name = nametab + name_offset;
656 1.1 christos
657 1.1 christos if (!(*pfn) (data, name, secoffset, secsize))
658 1.1 christos {
659 1.1 christos *errmsg = NULL;
660 1.1 christos *err = 0;
661 1.1 christos XDELETEVEC (index);
662 1.1 christos XDELETEVEC (nametab);
663 1.1 christos XDELETEVEC (strtab);
664 1.1 christos XDELETEVEC (secdata);
665 1.1 christos return 0;
666 1.1 christos }
667 1.1 christos }
668 1.1 christos continue;
669 1.1 christos }
670 1.1 christos }
671 1.1 christos
672 1.1 christos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0)
673 1.1 christos {
674 1.1 christos memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN);
675 1.1 christos namebuf[MACH_O_NAME_LEN] = '\0';
676 1.1 christos
677 1.1 christos name = &namebuf[0];
678 1.1 christos if (strtab != NULL && name[0] == '_' && name[1] == '_')
679 1.1 christos {
680 1.1 christos unsigned long stringoffset;
681 1.1 christos
682 1.1 christos if (sscanf (name + 2, "%08lX", &stringoffset) == 1)
683 1.1 christos {
684 1.1 christos if (stringoffset >= strtab_size)
685 1.1 christos {
686 1.1 christos *errmsg = "section name offset out of range";
687 1.1 christos *err = 0;
688 1.1 christos XDELETEVEC (index);
689 1.1 christos XDELETEVEC (nametab);
690 1.1 christos XDELETEVEC (strtab);
691 1.1 christos XDELETEVEC (secdata);
692 1.1 christos return 0;
693 1.1 christos }
694 1.1 christos
695 1.1 christos name = strtab + stringoffset;
696 1.1 christos }
697 1.1 christos }
698 1.1 christos }
699 1.1 christos else
700 1.1 christos {
701 1.1 christos /* Otherwise, make a name like __segment,__section as per the
702 1.1 christos convention in mach-o asm. */
703 1.1 christos name = &namebuf[0];
704 1.1 christos memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN);
705 1.1 christos namebuf[MACH_O_NAME_LEN] = '\0';
706 1.1 christos l = strlen (namebuf);
707 1.1 christos namebuf[l] = ',';
708 1.1 christos memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset,
709 1.1 christos MACH_O_NAME_LEN);
710 1.1 christos namebuf[l + 1 + MACH_O_NAME_LEN] = '\0';
711 1.1 christos }
712 1.1 christos
713 1.1 christos simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr,
714 1.1 christos &secoffset, &secsize);
715 1.1 christos
716 1.1 christos if (!(*pfn) (data, name, secoffset, secsize))
717 1.1 christos {
718 1.1 christos *errmsg = NULL;
719 1.1 christos *err = 0;
720 1.1 christos XDELETEVEC (index);
721 1.1 christos XDELETEVEC (nametab);
722 1.1 christos XDELETEVEC (strtab);
723 1.1 christos XDELETEVEC (secdata);
724 1.1 christos return 0;
725 1.1 christos }
726 1.1 christos }
727 1.1 christos
728 1.1 christos XDELETEVEC (index);
729 1.1 christos XDELETEVEC (nametab);
730 1.1 christos XDELETEVEC (strtab);
731 1.1 christos XDELETEVEC (secdata);
732 1.1 christos
733 1.1 christos return 1;
734 1.1 christos }
735 1.1 christos
736 1.1 christos /* Find all sections in a Mach-O file. */
737 1.1 christos
738 1.1 christos static const char *
739 1.1 christos simple_object_mach_o_find_sections (simple_object_read *sobj,
740 1.1 christos int (*pfn) (void *, const char *,
741 1.1 christos off_t offset, off_t length),
742 1.1 christos void *data,
743 1.1 christos int *err)
744 1.1 christos {
745 1.1 christos struct simple_object_mach_o_read *omr =
746 1.1 christos (struct simple_object_mach_o_read *) sobj->data;
747 1.1 christos off_t offset;
748 1.1 christos size_t seghdrsize;
749 1.1 christos unsigned int (*fetch_32) (const unsigned char *);
750 1.1 christos const char *errmsg;
751 1.1 christos unsigned int i;
752 1.1 christos
753 1.1 christos if (omr->magic == MACH_O_MH_MAGIC)
754 1.1 christos {
755 1.1 christos offset = sizeof (struct mach_o_header_32);
756 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_32);
757 1.1 christos }
758 1.1 christos else
759 1.1 christos {
760 1.1 christos offset = sizeof (struct mach_o_header_64);
761 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_64);
762 1.1 christos }
763 1.1 christos
764 1.1 christos fetch_32 = (omr->is_big_endian
765 1.1 christos ? simple_object_fetch_big_32
766 1.1 christos : simple_object_fetch_little_32);
767 1.1 christos
768 1.1 christos for (i = 0; i < omr->ncmds; ++i)
769 1.1 christos {
770 1.1 christos unsigned char loadbuf[sizeof (struct mach_o_load_command)];
771 1.1 christos unsigned int cmd;
772 1.1 christos unsigned int cmdsize;
773 1.1 christos
774 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
775 1.1 christos sobj->offset + offset,
776 1.1 christos loadbuf,
777 1.1 christos sizeof (struct mach_o_load_command),
778 1.1 christos &errmsg, err))
779 1.1 christos return errmsg;
780 1.1 christos
781 1.1 christos cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd));
782 1.1 christos cmdsize = (*fetch_32) (loadbuf
783 1.1 christos + offsetof (struct mach_o_load_command, cmdsize));
784 1.1 christos
785 1.1 christos if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64)
786 1.1 christos {
787 1.1 christos unsigned char segbuf[sizeof (struct mach_o_segment_command_64)];
788 1.1 christos int r;
789 1.1 christos
790 1.1 christos if (!simple_object_internal_read (sobj->descriptor,
791 1.1 christos sobj->offset + offset,
792 1.1 christos segbuf, seghdrsize, &errmsg, err))
793 1.1 christos return errmsg;
794 1.1 christos
795 1.1 christos r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn,
796 1.1 christos data, &errmsg, err);
797 1.1 christos if (!r)
798 1.1 christos return errmsg;
799 1.1 christos }
800 1.1 christos
801 1.1 christos offset += cmdsize;
802 1.1 christos }
803 1.1 christos
804 1.1 christos return NULL;
805 1.1 christos }
806 1.1 christos
807 1.1 christos /* Fetch the attributes for an simple_object_read. */
808 1.1 christos
809 1.1 christos static void *
810 1.1 christos simple_object_mach_o_fetch_attributes (simple_object_read *sobj,
811 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
812 1.1 christos int *err ATTRIBUTE_UNUSED)
813 1.1 christos {
814 1.1 christos struct simple_object_mach_o_read *omr =
815 1.1 christos (struct simple_object_mach_o_read *) sobj->data;
816 1.1 christos struct simple_object_mach_o_attributes *ret;
817 1.1 christos
818 1.1 christos ret = XNEW (struct simple_object_mach_o_attributes);
819 1.1 christos ret->magic = omr->magic;
820 1.1 christos ret->is_big_endian = omr->is_big_endian;
821 1.1 christos ret->cputype = omr->cputype;
822 1.1 christos ret->cpusubtype = omr->cpusubtype;
823 1.1 christos ret->flags = omr->flags;
824 1.1 christos ret->reserved = omr->reserved;
825 1.1 christos return ret;
826 1.1 christos }
827 1.1 christos
828 1.1 christos /* Release the private data for an simple_object_read. */
829 1.1 christos
830 1.1 christos static void
831 1.1 christos simple_object_mach_o_release_read (void *data)
832 1.1 christos {
833 1.1 christos struct simple_object_mach_o_read *omr =
834 1.1 christos (struct simple_object_mach_o_read *) data;
835 1.1 christos
836 1.1 christos free (omr->segment_name);
837 1.1 christos XDELETE (omr);
838 1.1 christos }
839 1.1 christos
840 1.1 christos /* Compare two attributes structures. */
841 1.1 christos
842 1.1 christos static const char *
843 1.1 christos simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err)
844 1.1 christos {
845 1.1 christos struct simple_object_mach_o_attributes *to =
846 1.1 christos (struct simple_object_mach_o_attributes *) todata;
847 1.1 christos struct simple_object_mach_o_attributes *from =
848 1.1 christos (struct simple_object_mach_o_attributes *) fromdata;
849 1.1 christos
850 1.1 christos if (to->magic != from->magic
851 1.1 christos || to->is_big_endian != from->is_big_endian
852 1.1 christos || to->cputype != from->cputype)
853 1.1 christos {
854 1.1 christos *err = 0;
855 1.1 christos return "Mach-O object format mismatch";
856 1.1 christos }
857 1.1 christos return NULL;
858 1.1 christos }
859 1.1 christos
860 1.1 christos /* Release the private data for an attributes structure. */
861 1.1 christos
862 1.1 christos static void
863 1.1 christos simple_object_mach_o_release_attributes (void *data)
864 1.1 christos {
865 1.1 christos XDELETE (data);
866 1.1 christos }
867 1.1 christos
868 1.1 christos /* Prepare to write out a file. */
869 1.1 christos
870 1.1 christos static void *
871 1.1 christos simple_object_mach_o_start_write (void *attributes_data,
872 1.1 christos const char **errmsg ATTRIBUTE_UNUSED,
873 1.1 christos int *err ATTRIBUTE_UNUSED)
874 1.1 christos {
875 1.1 christos struct simple_object_mach_o_attributes *attrs =
876 1.1 christos (struct simple_object_mach_o_attributes *) attributes_data;
877 1.1 christos struct simple_object_mach_o_attributes *ret;
878 1.1 christos
879 1.1 christos /* We're just going to record the attributes, but we need to make a
880 1.1 christos copy because the user may delete them. */
881 1.1 christos ret = XNEW (struct simple_object_mach_o_attributes);
882 1.1 christos *ret = *attrs;
883 1.1 christos return ret;
884 1.1 christos }
885 1.1 christos
886 1.1 christos /* Write out the header of a Mach-O file. */
887 1.1 christos
888 1.1 christos static int
889 1.1 christos simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor,
890 1.1 christos size_t nsects, const char **errmsg,
891 1.1 christos int *err)
892 1.1 christos {
893 1.1 christos struct simple_object_mach_o_attributes *attrs =
894 1.1 christos (struct simple_object_mach_o_attributes *) sobj->data;
895 1.1 christos void (*set_32) (unsigned char *, unsigned int);
896 1.1 christos unsigned char hdrbuf[sizeof (struct mach_o_header_64)];
897 1.1 christos unsigned char *hdr;
898 1.1 christos size_t wrsize;
899 1.1 christos
900 1.1 christos set_32 = (attrs->is_big_endian
901 1.1 christos ? simple_object_set_big_32
902 1.1 christos : simple_object_set_little_32);
903 1.1 christos
904 1.1 christos memset (hdrbuf, 0, sizeof hdrbuf);
905 1.1 christos
906 1.1 christos /* The 32-bit and 64-bit headers start out the same. */
907 1.1 christos
908 1.1 christos hdr = &hdrbuf[0];
909 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic);
910 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype);
911 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype),
912 1.1 christos attrs->cpusubtype);
913 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT);
914 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1);
915 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags);
916 1.1 christos if (attrs->magic == MACH_O_MH_MAGIC)
917 1.1 christos {
918 1.1 christos wrsize = sizeof (struct mach_o_header_32);
919 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds),
920 1.1 christos (sizeof (struct mach_o_segment_command_32)
921 1.1 christos + nsects * sizeof (struct mach_o_section_32)));
922 1.1 christos }
923 1.1 christos else
924 1.1 christos {
925 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds),
926 1.1 christos (sizeof (struct mach_o_segment_command_64)
927 1.1 christos + nsects * sizeof (struct mach_o_section_64)));
928 1.1 christos set_32 (hdr + offsetof (struct mach_o_header_64, reserved),
929 1.1 christos attrs->reserved);
930 1.1 christos wrsize = sizeof (struct mach_o_header_64);
931 1.1 christos }
932 1.1 christos
933 1.1 christos return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize,
934 1.1 christos errmsg, err);
935 1.1 christos }
936 1.1 christos
937 1.1 christos /* Write a Mach-O section header. */
938 1.1 christos
939 1.1 christos static int
940 1.1 christos simple_object_mach_o_write_section_header (simple_object_write *sobj,
941 1.1 christos int descriptor,
942 1.1 christos size_t sechdr_offset,
943 1.1 christos const char *name, const char *segn,
944 1.1 christos size_t secaddr, size_t secsize,
945 1.1 christos size_t offset, unsigned int align,
946 1.1 christos const char **errmsg, int *err)
947 1.1 christos {
948 1.1 christos struct simple_object_mach_o_attributes *attrs =
949 1.1 christos (struct simple_object_mach_o_attributes *) sobj->data;
950 1.1 christos void (*set_32) (unsigned char *, unsigned int);
951 1.1 christos unsigned char hdrbuf[sizeof (struct mach_o_section_64)];
952 1.1 christos unsigned char *hdr;
953 1.1 christos size_t sechdrsize;
954 1.1 christos
955 1.1 christos set_32 = (attrs->is_big_endian
956 1.1 christos ? simple_object_set_big_32
957 1.1 christos : simple_object_set_little_32);
958 1.1 christos
959 1.1 christos memset (hdrbuf, 0, sizeof hdrbuf);
960 1.1 christos
961 1.1 christos hdr = &hdrbuf[0];
962 1.1 christos if (attrs->magic == MACH_O_MH_MAGIC)
963 1.1 christos {
964 1.1 christos strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname),
965 1.1 christos name, MACH_O_NAME_LEN);
966 1.1 christos strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname),
967 1.1 christos segn, MACH_O_NAME_LEN);
968 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr);
969 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize);
970 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset);
971 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_32, align), align);
972 1.1 christos /* reloff left as zero. */
973 1.1 christos /* nreloc left as zero. */
974 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_32, flags),
975 1.1 christos MACH_O_S_ATTR_DEBUG);
976 1.1 christos /* reserved1 left as zero. */
977 1.1 christos /* reserved2 left as zero. */
978 1.1 christos sechdrsize = sizeof (struct mach_o_section_32);
979 1.1 christos }
980 1.1 christos else
981 1.1 christos {
982 1.1 christos #ifdef UNSIGNED_64BIT_TYPE
983 1.1 christos void (*set_64) (unsigned char *, ulong_type);
984 1.1 christos
985 1.1 christos set_64 = (attrs->is_big_endian
986 1.1 christos ? simple_object_set_big_64
987 1.1 christos : simple_object_set_little_64);
988 1.1 christos
989 1.1 christos strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname),
990 1.1 christos name, MACH_O_NAME_LEN);
991 1.1 christos strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname),
992 1.1 christos segn, MACH_O_NAME_LEN);
993 1.1 christos set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr);
994 1.1 christos set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize);
995 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset);
996 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_64, align), align);
997 1.1 christos /* reloff left as zero. */
998 1.1 christos /* nreloc left as zero. */
999 1.1 christos set_32 (hdr + offsetof (struct mach_o_section_64, flags),
1000 1.1 christos MACH_O_S_ATTR_DEBUG);
1001 1.1 christos /* reserved1 left as zero. */
1002 1.1 christos /* reserved2 left as zero. */
1003 1.1 christos /* reserved3 left as zero. */
1004 1.1 christos #endif
1005 1.1 christos sechdrsize = sizeof (struct mach_o_section_64);
1006 1.1 christos }
1007 1.1 christos
1008 1.1 christos return simple_object_internal_write (descriptor, sechdr_offset, hdr,
1009 1.1 christos sechdrsize, errmsg, err);
1010 1.1 christos }
1011 1.1 christos
1012 1.1 christos /* Write out the single (anonymous) segment containing the sections of a Mach-O
1013 1.1 christos Object file.
1014 1.1 christos
1015 1.1 christos As a GNU extension to mach-o, when the caller specifies a segment name in
1016 1.1 christos sobj->segment_name, all the sections passed will be output under a single
1017 1.1 christos mach-o section header. The caller's sections are indexed within this
1018 1.1 christos 'wrapper' section by a table stored in a second mach-o section. Finally,
1019 1.1 christos arbitrary length section names are permitted by the extension and these are
1020 1.1 christos stored in a table in a third mach-o section.
1021 1.1 christos
1022 1.1 christos Note that this is only likely to make any sense for the __GNU_LTO segment
1023 1.1 christos at present.
1024 1.1 christos
1025 1.1 christos If the wrapper extension is not in force, we assume that the section name
1026 1.1 christos is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */
1027 1.1 christos
1028 1.1 christos static int
1029 1.1 christos simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor,
1030 1.1 christos size_t *nsects, const char **errmsg,
1031 1.1 christos int *err)
1032 1.1 christos {
1033 1.1 christos struct simple_object_mach_o_attributes *attrs =
1034 1.1 christos (struct simple_object_mach_o_attributes *) sobj->data;
1035 1.1 christos void (*set_32) (unsigned char *, unsigned int);
1036 1.1 christos size_t hdrsize;
1037 1.1 christos size_t seghdrsize;
1038 1.1 christos size_t sechdrsize;
1039 1.1 christos size_t cmdsize;
1040 1.1 christos size_t offset;
1041 1.1 christos size_t sechdr_offset;
1042 1.1 christos size_t secaddr;
1043 1.1 christos unsigned int name_offset;
1044 1.1 christos simple_object_write_section *section;
1045 1.1 christos unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)];
1046 1.1 christos unsigned char *hdr;
1047 1.1 christos size_t nsects_in;
1048 1.1 christos unsigned int *index;
1049 1.1 christos char *snames;
1050 1.1 christos unsigned int sect;
1051 1.1 christos
1052 1.1 christos set_32 = (attrs->is_big_endian
1053 1.1 christos ? simple_object_set_big_32
1054 1.1 christos : simple_object_set_little_32);
1055 1.1 christos
1056 1.1 christos /* Write out the sections first. */
1057 1.1 christos
1058 1.1 christos if (attrs->magic == MACH_O_MH_MAGIC)
1059 1.1 christos {
1060 1.1 christos hdrsize = sizeof (struct mach_o_header_32);
1061 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_32);
1062 1.1 christos sechdrsize = sizeof (struct mach_o_section_32);
1063 1.1 christos }
1064 1.1 christos else
1065 1.1 christos {
1066 1.1 christos hdrsize = sizeof (struct mach_o_header_64);
1067 1.1 christos seghdrsize = sizeof (struct mach_o_segment_command_64);
1068 1.1 christos sechdrsize = sizeof (struct mach_o_section_64);
1069 1.1 christos }
1070 1.1 christos
1071 1.1 christos name_offset = 0;
1072 1.1 christos *nsects = nsects_in = 0;
1073 1.1 christos
1074 1.1 christos /* Count the number of sections we start with. */
1075 1.1 christos
1076 1.1 christos for (section = sobj->sections; section != NULL; section = section->next)
1077 1.1 christos nsects_in++;
1078 1.1 christos
1079 1.1 christos if (sobj->segment_name != NULL)
1080 1.1 christos {
1081 1.1 christos /* We will only write 3 sections: wrapped data, index and names. */
1082 1.1 christos
1083 1.1 christos *nsects = 3;
1084 1.1 christos
1085 1.1 christos /* The index has four entries per wrapped section:
1086 1.1 christos Section Offset, length, Name offset, length.
1087 1.1 christos Where the offsets are based at the start of the wrapper and name
1088 1.1 christos sections respectively.
1089 1.1 christos The values are stored as 32 bit int for both 32 and 64 bit mach-o
1090 1.1 christos since the size of a mach-o MH_OBJECT cannot exceed 4G owing to
1091 1.1 christos other constraints. */
1092 1.1 christos
1093 1.1 christos index = XNEWVEC (unsigned int, nsects_in * 4);
1094 1.1 christos
1095 1.1 christos /* We now need to figure out the size of the names section. This just
1096 1.1 christos stores the names as null-terminated c strings, packed without any
1097 1.1 christos alignment padding. */
1098 1.1 christos
1099 1.1 christos for (section = sobj->sections, sect = 0; section != NULL;
1100 1.1 christos section = section->next, sect++)
1101 1.1 christos {
1102 1.1 christos index[sect*4+2] = name_offset;
1103 1.1 christos index[sect*4+3] = strlen (section->name) + 1;
1104 1.1 christos name_offset += strlen (section->name) + 1;
1105 1.1 christos }
1106 1.1 christos snames = XNEWVEC (char, name_offset);
1107 1.1 christos }
1108 1.1 christos else
1109 1.1 christos {
1110 1.1 christos *nsects = nsects_in;
1111 1.1 christos index = NULL;
1112 1.1 christos snames = NULL;
1113 1.1 christos }
1114 1.1 christos
1115 1.1 christos sechdr_offset = hdrsize + seghdrsize;
1116 1.1 christos cmdsize = seghdrsize + *nsects * sechdrsize;
1117 1.1 christos offset = hdrsize + cmdsize;
1118 1.1 christos secaddr = 0;
1119 1.1 christos
1120 1.1 christos for (section = sobj->sections, sect = 0;
1121 1.1 christos section != NULL; section = section->next, sect++)
1122 1.1 christos {
1123 1.1 christos size_t mask;
1124 1.1 christos size_t new_offset;
1125 1.1 christos size_t secsize;
1126 1.1 christos struct simple_object_write_section_buffer *buffer;
1127 1.1 christos
1128 1.1 christos mask = (1U << section->align) - 1;
1129 1.1 christos new_offset = offset + mask;
1130 1.1 christos new_offset &= ~ mask;
1131 1.1 christos while (new_offset > offset)
1132 1.1 christos {
1133 1.1 christos unsigned char zeroes[16];
1134 1.1 christos size_t write;
1135 1.1 christos
1136 1.1 christos memset (zeroes, 0, sizeof zeroes);
1137 1.1 christos write = new_offset - offset;
1138 1.1 christos if (write > sizeof zeroes)
1139 1.1 christos write = sizeof zeroes;
1140 1.1 christos if (!simple_object_internal_write (descriptor, offset, zeroes, write,
1141 1.1 christos errmsg, err))
1142 1.1 christos return 0;
1143 1.1 christos offset += write;
1144 1.1 christos }
1145 1.1 christos
1146 1.1 christos secsize = 0;
1147 1.1 christos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next)
1148 1.1 christos {
1149 1.1 christos if (!simple_object_internal_write (descriptor, offset + secsize,
1150 1.1 christos ((const unsigned char *)
1151 1.1 christos buffer->buffer),
1152 1.1 christos buffer->size, errmsg, err))
1153 1.1 christos return 0;
1154 1.1 christos secsize += buffer->size;
1155 1.1 christos }
1156 1.1 christos
1157 1.1 christos if (sobj->segment_name != NULL)
1158 1.1 christos {
1159 1.1 christos index[sect*4+0] = (unsigned int) offset;
1160 1.1 christos index[sect*4+1] = secsize;
1161 1.1 christos /* Stash the section name in our table. */
1162 1.1 christos memcpy (snames + index[sect * 4 + 2], section->name,
1163 1.1 christos index[sect * 4 + 3]);
1164 1.1 christos }
1165 1.1 christos else
1166 1.1 christos {
1167 1.1 christos char namebuf[MACH_O_NAME_LEN + 1];
1168 1.1 christos char segnbuf[MACH_O_NAME_LEN + 1];
1169 1.1 christos char *comma;
1170 1.1 christos
1171 1.1 christos /* Try to extract segment,section from the input name. */
1172 1.1 christos
1173 1.1 christos memset (namebuf, 0, sizeof namebuf);
1174 1.1 christos memset (segnbuf, 0, sizeof segnbuf);
1175 1.1 christos comma = strchr (section->name, ',');
1176 1.1 christos if (comma != NULL)
1177 1.1 christos {
1178 1.1 christos int len = comma - section->name;
1179 1.1 christos len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len;
1180 1.1 christos strncpy (namebuf, section->name, len);
1181 1.1 christos strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN);
1182 1.1 christos }
1183 1.1 christos else /* just try to copy the name, leave segment blank. */
1184 1.1 christos strncpy (namebuf, section->name, MACH_O_NAME_LEN);
1185 1.1 christos
1186 1.1 christos if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1187 1.1 christos sechdr_offset,
1188 1.1 christos namebuf, segnbuf,
1189 1.1 christos secaddr, secsize,
1190 1.1 christos offset,
1191 1.1 christos section->align,
1192 1.1 christos errmsg, err))
1193 1.1 christos return 0;
1194 1.1 christos sechdr_offset += sechdrsize;
1195 1.1 christos }
1196 1.1 christos
1197 1.1 christos offset += secsize;
1198 1.1 christos secaddr += secsize;
1199 1.1 christos }
1200 1.1 christos
1201 1.1 christos if (sobj->segment_name != NULL)
1202 1.1 christos {
1203 1.1 christos size_t secsize;
1204 1.1 christos unsigned int i;
1205 1.1 christos
1206 1.1 christos /* Write the section header for the wrapper. */
1207 1.1 christos /* Account for any initial aligment - which becomes the alignment for this
1208 1.1 christos created section. */
1209 1.1 christos
1210 1.1 christos secsize = (offset - index[0]);
1211 1.1 christos if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1212 1.1 christos sechdr_offset,
1213 1.1 christos GNU_WRAPPER_SECTS,
1214 1.1 christos sobj->segment_name,
1215 1.1 christos 0 /*secaddr*/,
1216 1.1 christos secsize, index[0],
1217 1.1 christos sobj->sections->align,
1218 1.1 christos errmsg, err))
1219 1.1 christos return 0;
1220 1.1 christos
1221 1.1 christos /* Subtract the wrapper section start from the begining of each sub
1222 1.1 christos section. */
1223 1.1 christos
1224 1.1 christos for (i = 1; i < nsects_in; ++i)
1225 1.1 christos index[4 * i] -= index[0];
1226 1.1 christos index[0] = 0;
1227 1.1 christos
1228 1.1 christos sechdr_offset += sechdrsize;
1229 1.1 christos
1230 1.1 christos /* Write out the section names.
1231 1.1 christos ... the header ...
1232 1.1 christos name_offset contains the length of the section. It is not aligned. */
1233 1.1 christos
1234 1.1 christos if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1235 1.1 christos sechdr_offset,
1236 1.1 christos GNU_WRAPPER_NAMES,
1237 1.1 christos sobj->segment_name,
1238 1.1 christos 0 /*secaddr*/,
1239 1.1 christos name_offset,
1240 1.1 christos offset,
1241 1.1 christos 0, errmsg, err))
1242 1.1 christos return 0;
1243 1.1 christos
1244 1.1 christos /* ... and the content.. */
1245 1.1 christos if (!simple_object_internal_write (descriptor, offset,
1246 1.1 christos (const unsigned char *) snames,
1247 1.1 christos name_offset, errmsg, err))
1248 1.1 christos return 0;
1249 1.1 christos
1250 1.1 christos sechdr_offset += sechdrsize;
1251 1.1 christos secaddr += name_offset;
1252 1.1 christos offset += name_offset;
1253 1.1 christos
1254 1.1 christos /* Now do the index, we'll align this to 4 bytes although the read code
1255 1.1 christos will handle unaligned. */
1256 1.1 christos
1257 1.1 christos offset += 3;
1258 1.1 christos offset &= ~0x03;
1259 1.1 christos if (!simple_object_mach_o_write_section_header (sobj, descriptor,
1260 1.1 christos sechdr_offset,
1261 1.1 christos GNU_WRAPPER_INDEX,
1262 1.1 christos sobj->segment_name,
1263 1.1 christos 0 /*secaddr*/,
1264 1.1 christos nsects_in * 16,
1265 1.1 christos offset,
1266 1.1 christos 2, errmsg, err))
1267 1.1 christos return 0;
1268 1.1 christos
1269 1.1 christos /* ... and the content.. */
1270 1.1 christos if (!simple_object_internal_write (descriptor, offset,
1271 1.1 christos (const unsigned char *) index,
1272 1.1 christos nsects_in*16, errmsg, err))
1273 1.1 christos return 0;
1274 1.1 christos
1275 1.1 christos XDELETEVEC (index);
1276 1.1 christos XDELETEVEC (snames);
1277 1.1 christos }
1278 1.1 christos
1279 1.1 christos /* Write out the segment header. */
1280 1.1 christos
1281 1.1 christos memset (hdrbuf, 0, sizeof hdrbuf);
1282 1.1 christos
1283 1.1 christos hdr = &hdrbuf[0];
1284 1.1 christos if (attrs->magic == MACH_O_MH_MAGIC)
1285 1.1 christos {
1286 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd),
1287 1.1 christos MACH_O_LC_SEGMENT);
1288 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize),
1289 1.1 christos cmdsize);
1290 1.1 christos /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1291 1.1 christos is left empty. */
1292 1.1 christos /* vmaddr left as zero. */
1293 1.1 christos /* vmsize left as zero. */
1294 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff),
1295 1.1 christos hdrsize + cmdsize);
1296 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize),
1297 1.1 christos offset - (hdrsize + cmdsize));
1298 1.1 christos /* maxprot left as zero. */
1299 1.1 christos /* initprot left as zero. */
1300 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects),
1301 1.1 christos *nsects);
1302 1.1 christos /* flags left as zero. */
1303 1.1 christos }
1304 1.1 christos else
1305 1.1 christos {
1306 1.1 christos #ifdef UNSIGNED_64BIT_TYPE
1307 1.1 christos void (*set_64) (unsigned char *, ulong_type);
1308 1.1 christos
1309 1.1 christos set_64 = (attrs->is_big_endian
1310 1.1 christos ? simple_object_set_big_64
1311 1.1 christos : simple_object_set_little_64);
1312 1.1 christos
1313 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd),
1314 1.1 christos MACH_O_LC_SEGMENT);
1315 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize),
1316 1.1 christos cmdsize);
1317 1.1 christos /* MH_OBJECTS have a single, anonymous, segment - so the segment name
1318 1.1 christos is left empty. */
1319 1.1 christos /* vmaddr left as zero. */
1320 1.1 christos /* vmsize left as zero. */
1321 1.1 christos set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff),
1322 1.1 christos hdrsize + cmdsize);
1323 1.1 christos set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize),
1324 1.1 christos offset - (hdrsize + cmdsize));
1325 1.1 christos /* maxprot left as zero. */
1326 1.1 christos /* initprot left as zero. */
1327 1.1 christos set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects),
1328 1.1 christos *nsects);
1329 1.1 christos /* flags left as zero. */
1330 1.1 christos #endif
1331 1.1 christos }
1332 1.1 christos
1333 1.1 christos return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize,
1334 1.1 christos errmsg, err);
1335 1.1 christos }
1336 1.1 christos
1337 1.1 christos /* Write out a complete Mach-O file. */
1338 1.1 christos
1339 1.1 christos static const char *
1340 1.1 christos simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor,
1341 1.1 christos int *err)
1342 1.1 christos {
1343 1.1 christos size_t nsects = 0;
1344 1.1 christos const char *errmsg;
1345 1.1 christos
1346 1.1 christos if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects,
1347 1.1 christos &errmsg, err))
1348 1.1 christos return errmsg;
1349 1.1 christos
1350 1.1 christos if (!simple_object_mach_o_write_header (sobj, descriptor, nsects,
1351 1.1 christos &errmsg, err))
1352 1.1 christos return errmsg;
1353 1.1 christos
1354 1.1 christos return NULL;
1355 1.1 christos }
1356 1.1 christos
1357 1.1 christos /* Release the private data for an simple_object_write structure. */
1358 1.1 christos
1359 1.1 christos static void
1360 1.1 christos simple_object_mach_o_release_write (void *data)
1361 1.1 christos {
1362 1.1 christos XDELETE (data);
1363 1.1 christos }
1364 1.1 christos
1365 1.1 christos /* The Mach-O functions. */
1366 1.1 christos
1367 1.1 christos const struct simple_object_functions simple_object_mach_o_functions =
1368 1.1 christos {
1369 1.1 christos simple_object_mach_o_match,
1370 1.1 christos simple_object_mach_o_find_sections,
1371 1.1 christos simple_object_mach_o_fetch_attributes,
1372 1.1 christos simple_object_mach_o_release_read,
1373 1.1 christos simple_object_mach_o_attributes_merge,
1374 1.1 christos simple_object_mach_o_release_attributes,
1375 1.1 christos simple_object_mach_o_start_write,
1376 1.1 christos simple_object_mach_o_write_to_file,
1377 1.1.1.3 christos simple_object_mach_o_release_write,
1378 1.1.1.3 christos NULL
1379 1.1 christos };
1380