xref: /dflybsd-src/contrib/gcc-8.0/libiberty/simple-object-mach-o.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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