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