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