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