198b9484cSchristos /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. 2*5173eb0aSchristos Copyright (C) 2010-2024 Free Software Foundation, Inc. 398b9484cSchristos Written by Ian Lance Taylor, Google. 498b9484cSchristos 598b9484cSchristos This program is free software; you can redistribute it and/or modify it 698b9484cSchristos under the terms of the GNU General Public License as published by the 798b9484cSchristos Free Software Foundation; either version 2, or (at your option) any 898b9484cSchristos later version. 998b9484cSchristos 1098b9484cSchristos This program is distributed in the hope that it will be useful, 1198b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1298b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1398b9484cSchristos GNU General Public License for more details. 1498b9484cSchristos 1598b9484cSchristos You should have received a copy of the GNU General Public License 1698b9484cSchristos along with this program; if not, write to the Free Software 1798b9484cSchristos Foundation, 51 Franklin Street - Fifth Floor, 1898b9484cSchristos Boston, MA 02110-1301, USA. */ 1998b9484cSchristos 2098b9484cSchristos #include "config.h" 2198b9484cSchristos #include "libiberty.h" 2298b9484cSchristos #include "simple-object.h" 2398b9484cSchristos 2498b9484cSchristos #include <stddef.h> 2598b9484cSchristos 2698b9484cSchristos #ifdef HAVE_STDLIB_H 2798b9484cSchristos #include <stdlib.h> 2898b9484cSchristos #endif 2998b9484cSchristos 3098b9484cSchristos #ifdef HAVE_STDINT_H 3198b9484cSchristos #include <stdint.h> 3298b9484cSchristos #endif 3398b9484cSchristos 3498b9484cSchristos #ifdef HAVE_STRING_H 3598b9484cSchristos #include <string.h> 3698b9484cSchristos #endif 3798b9484cSchristos 3898b9484cSchristos #ifdef HAVE_INTTYPES_H 3998b9484cSchristos #include <inttypes.h> 4098b9484cSchristos #endif 4198b9484cSchristos 4298b9484cSchristos #include "simple-object-common.h" 4398b9484cSchristos 4498b9484cSchristos /* Mach-O structures and constants. */ 4598b9484cSchristos 4698b9484cSchristos /* Mach-O header (32-bit version). */ 4798b9484cSchristos 4898b9484cSchristos struct mach_o_header_32 4998b9484cSchristos { 5098b9484cSchristos unsigned char magic[4]; /* Magic number. */ 5198b9484cSchristos unsigned char cputype[4]; /* CPU that this object is for. */ 5298b9484cSchristos unsigned char cpusubtype[4]; /* CPU subtype. */ 5398b9484cSchristos unsigned char filetype[4]; /* Type of file. */ 5498b9484cSchristos unsigned char ncmds[4]; /* Number of load commands. */ 5598b9484cSchristos unsigned char sizeofcmds[4]; /* Total size of load commands. */ 5698b9484cSchristos unsigned char flags[4]; /* Flags for special featues. */ 5798b9484cSchristos }; 5898b9484cSchristos 5998b9484cSchristos /* Mach-O header (64-bit version). */ 6098b9484cSchristos 6198b9484cSchristos struct mach_o_header_64 6298b9484cSchristos { 6398b9484cSchristos unsigned char magic[4]; /* Magic number. */ 6498b9484cSchristos unsigned char cputype[4]; /* CPU that this object is for. */ 6598b9484cSchristos unsigned char cpusubtype[4]; /* CPU subtype. */ 6698b9484cSchristos unsigned char filetype[4]; /* Type of file. */ 6798b9484cSchristos unsigned char ncmds[4]; /* Number of load commands. */ 6898b9484cSchristos unsigned char sizeofcmds[4]; /* Total size of load commands. */ 6998b9484cSchristos unsigned char flags[4]; /* Flags for special featues. */ 7098b9484cSchristos unsigned char reserved[4]; /* Reserved. Duh. */ 7198b9484cSchristos }; 7298b9484cSchristos 7398b9484cSchristos /* For magic field in header. */ 7498b9484cSchristos 7598b9484cSchristos #define MACH_O_MH_MAGIC 0xfeedface 7698b9484cSchristos #define MACH_O_MH_MAGIC_64 0xfeedfacf 7798b9484cSchristos 7898b9484cSchristos /* For filetype field in header. */ 7998b9484cSchristos 8098b9484cSchristos #define MACH_O_MH_OBJECT 0x01 8198b9484cSchristos 8298b9484cSchristos /* A Mach-O file is a list of load commands. This is the header of a 8398b9484cSchristos load command. */ 8498b9484cSchristos 8598b9484cSchristos struct mach_o_load_command 8698b9484cSchristos { 8798b9484cSchristos unsigned char cmd[4]; /* The type of load command. */ 8898b9484cSchristos unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 8998b9484cSchristos }; 9098b9484cSchristos 9198b9484cSchristos /* For cmd field in load command. */ 9298b9484cSchristos 9398b9484cSchristos #define MACH_O_LC_SEGMENT 0x01 9498b9484cSchristos #define MACH_O_LC_SEGMENT_64 0x19 9598b9484cSchristos 9698b9484cSchristos /* LC_SEGMENT load command. */ 9798b9484cSchristos 9898b9484cSchristos struct mach_o_segment_command_32 9998b9484cSchristos { 10098b9484cSchristos unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */ 10198b9484cSchristos unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 10298b9484cSchristos unsigned char segname[16]; /* Name of this segment. */ 10398b9484cSchristos unsigned char vmaddr[4]; /* Virtual memory address of this segment. */ 10498b9484cSchristos unsigned char vmsize[4]; /* Size there, in bytes. */ 10598b9484cSchristos unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */ 10698b9484cSchristos unsigned char filesize[4]; /* Size in bytes on disk. */ 10798b9484cSchristos unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 10898b9484cSchristos unsigned char initprot[4]; /* Initial vmem protection. */ 10998b9484cSchristos unsigned char nsects[4]; /* Number of sections in this segment. */ 11098b9484cSchristos unsigned char flags[4]; /* Flags that affect the loading. */ 11198b9484cSchristos }; 11298b9484cSchristos 11398b9484cSchristos /* LC_SEGMENT_64 load command. */ 11498b9484cSchristos 11598b9484cSchristos struct mach_o_segment_command_64 11698b9484cSchristos { 11798b9484cSchristos unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */ 11898b9484cSchristos unsigned char cmdsize[4]; /* Size in bytes of entire command. */ 11998b9484cSchristos unsigned char segname[16]; /* Name of this segment. */ 12098b9484cSchristos unsigned char vmaddr[8]; /* Virtual memory address of this segment. */ 12198b9484cSchristos unsigned char vmsize[8]; /* Size there, in bytes. */ 12298b9484cSchristos unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */ 12398b9484cSchristos unsigned char filesize[8]; /* Size in bytes on disk. */ 12498b9484cSchristos unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ 12598b9484cSchristos unsigned char initprot[4]; /* Initial vmem protection. */ 12698b9484cSchristos unsigned char nsects[4]; /* Number of sections in this segment. */ 12798b9484cSchristos unsigned char flags[4]; /* Flags that affect the loading. */ 12898b9484cSchristos }; 12998b9484cSchristos 13098b9484cSchristos /* 32-bit section header. */ 13198b9484cSchristos 13298b9484cSchristos struct mach_o_section_32 13398b9484cSchristos { 13498b9484cSchristos unsigned char sectname[16]; /* Section name. */ 13598b9484cSchristos unsigned char segname[16]; /* Segment that the section belongs to. */ 13698b9484cSchristos unsigned char addr[4]; /* Address of this section in memory. */ 13798b9484cSchristos unsigned char size[4]; /* Size in bytes of this section. */ 13898b9484cSchristos unsigned char offset[4]; /* File offset of this section. */ 13998b9484cSchristos unsigned char align[4]; /* log2 of this section's alignment. */ 14098b9484cSchristos unsigned char reloff[4]; /* File offset of this section's relocs. */ 14198b9484cSchristos unsigned char nreloc[4]; /* Number of relocs for this section. */ 14298b9484cSchristos unsigned char flags[4]; /* Section flags/attributes. */ 14398b9484cSchristos unsigned char reserved1[4]; 14498b9484cSchristos unsigned char reserved2[4]; 14598b9484cSchristos }; 14698b9484cSchristos 14798b9484cSchristos /* 64-bit section header. */ 14898b9484cSchristos 14998b9484cSchristos struct mach_o_section_64 15098b9484cSchristos { 15198b9484cSchristos unsigned char sectname[16]; /* Section name. */ 15298b9484cSchristos unsigned char segname[16]; /* Segment that the section belongs to. */ 15398b9484cSchristos unsigned char addr[8]; /* Address of this section in memory. */ 15498b9484cSchristos unsigned char size[8]; /* Size in bytes of this section. */ 15598b9484cSchristos unsigned char offset[4]; /* File offset of this section. */ 15698b9484cSchristos unsigned char align[4]; /* log2 of this section's alignment. */ 15798b9484cSchristos unsigned char reloff[4]; /* File offset of this section's relocs. */ 15898b9484cSchristos unsigned char nreloc[4]; /* Number of relocs for this section. */ 15998b9484cSchristos unsigned char flags[4]; /* Section flags/attributes. */ 16098b9484cSchristos unsigned char reserved1[4]; 16198b9484cSchristos unsigned char reserved2[4]; 16298b9484cSchristos unsigned char reserved3[4]; 16398b9484cSchristos }; 16498b9484cSchristos 16598b9484cSchristos /* Flags for Mach-O sections. */ 16698b9484cSchristos 16798b9484cSchristos #define MACH_O_S_ATTR_DEBUG 0x02000000 16898b9484cSchristos 16998b9484cSchristos /* The length of a segment or section name. */ 17098b9484cSchristos 17198b9484cSchristos #define MACH_O_NAME_LEN (16) 17298b9484cSchristos 17398b9484cSchristos /* A GNU specific extension for long section names. */ 17498b9484cSchristos 17598b9484cSchristos #define GNU_SECTION_NAMES "__section_names" 17698b9484cSchristos 177a2e2270fSchristos /* A GNU-specific extension to wrap multiple sections using three 178a2e2270fSchristos mach-o sections within a given segment. The section '__wrapper_sects' 179a2e2270fSchristos is subdivided according to the index '__wrapper_index' and each sub 180a2e2270fSchristos sect is named according to the names supplied in '__wrapper_names'. */ 181a2e2270fSchristos 182a2e2270fSchristos #define GNU_WRAPPER_SECTS "__wrapper_sects" 183a2e2270fSchristos #define GNU_WRAPPER_INDEX "__wrapper_index" 184a2e2270fSchristos #define GNU_WRAPPER_NAMES "__wrapper_names" 185a2e2270fSchristos 18698b9484cSchristos /* Private data for an simple_object_read. */ 18798b9484cSchristos 18898b9484cSchristos struct simple_object_mach_o_read 18998b9484cSchristos { 19098b9484cSchristos /* User specified segment name. */ 19198b9484cSchristos char *segment_name; 19298b9484cSchristos /* Magic number. */ 19398b9484cSchristos unsigned int magic; 19498b9484cSchristos /* Whether this file is big-endian. */ 19598b9484cSchristos int is_big_endian; 19698b9484cSchristos /* CPU type from header. */ 19798b9484cSchristos unsigned int cputype; 19898b9484cSchristos /* CPU subtype from header. */ 19998b9484cSchristos unsigned int cpusubtype; 20098b9484cSchristos /* Number of commands, from header. */ 20198b9484cSchristos unsigned int ncmds; 20298b9484cSchristos /* Flags from header. */ 20398b9484cSchristos unsigned int flags; 20498b9484cSchristos /* Reserved field from header, only used on 64-bit. */ 20598b9484cSchristos unsigned int reserved; 20698b9484cSchristos }; 20798b9484cSchristos 20898b9484cSchristos /* Private data for an simple_object_attributes. */ 20998b9484cSchristos 21098b9484cSchristos struct simple_object_mach_o_attributes 21198b9484cSchristos { 21298b9484cSchristos /* Magic number. */ 21398b9484cSchristos unsigned int magic; 21498b9484cSchristos /* Whether this file is big-endian. */ 21598b9484cSchristos int is_big_endian; 21698b9484cSchristos /* CPU type from header. */ 21798b9484cSchristos unsigned int cputype; 21898b9484cSchristos /* CPU subtype from header. */ 21998b9484cSchristos unsigned int cpusubtype; 22098b9484cSchristos /* Flags from header. */ 22198b9484cSchristos unsigned int flags; 22298b9484cSchristos /* Reserved field from header, only used on 64-bit. */ 22398b9484cSchristos unsigned int reserved; 22498b9484cSchristos }; 22598b9484cSchristos 226a2e2270fSchristos /* See if we have a Mach-O MH_OBJECT file: 227a2e2270fSchristos 228a2e2270fSchristos A standard MH_OBJECT (from as) will have three load commands: 229a2e2270fSchristos 0 - LC_SEGMENT/LC_SEGMENT64 230a2e2270fSchristos 1 - LC_SYMTAB 231a2e2270fSchristos 2 - LC_DYSYMTAB 232a2e2270fSchristos 233a2e2270fSchristos The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment 234a2e2270fSchristos containing all the sections. 235a2e2270fSchristos 236a2e2270fSchristos Files written by simple-object will have only the segment command 237a2e2270fSchristos (no symbol tables). */ 23898b9484cSchristos 23998b9484cSchristos static void * 24098b9484cSchristos simple_object_mach_o_match ( 24198b9484cSchristos unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], 24298b9484cSchristos int descriptor, 24398b9484cSchristos off_t offset, 24498b9484cSchristos const char *segment_name, 24598b9484cSchristos const char **errmsg, 24698b9484cSchristos int *err) 24798b9484cSchristos { 24898b9484cSchristos unsigned int magic; 24998b9484cSchristos int is_big_endian; 25098b9484cSchristos unsigned int (*fetch_32) (const unsigned char *); 25198b9484cSchristos unsigned int filetype; 25298b9484cSchristos struct simple_object_mach_o_read *omr; 25398b9484cSchristos unsigned char buf[sizeof (struct mach_o_header_64)]; 25498b9484cSchristos unsigned char *b; 25598b9484cSchristos 25698b9484cSchristos magic = simple_object_fetch_big_32 (header); 25798b9484cSchristos if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 25898b9484cSchristos is_big_endian = 1; 25998b9484cSchristos else 26098b9484cSchristos { 26198b9484cSchristos magic = simple_object_fetch_little_32 (header); 26298b9484cSchristos if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) 26398b9484cSchristos is_big_endian = 0; 26498b9484cSchristos else 26598b9484cSchristos { 26698b9484cSchristos *errmsg = NULL; 26798b9484cSchristos *err = 0; 26898b9484cSchristos return NULL; 26998b9484cSchristos } 27098b9484cSchristos } 27198b9484cSchristos 27298b9484cSchristos #ifndef UNSIGNED_64BIT_TYPE 27398b9484cSchristos if (magic == MACH_O_MH_MAGIC_64) 27498b9484cSchristos { 27598b9484cSchristos *errmsg = "64-bit Mach-O objects not supported"; 27698b9484cSchristos *err = 0; 27798b9484cSchristos return NULL; 27898b9484cSchristos } 27998b9484cSchristos #endif 28098b9484cSchristos 28198b9484cSchristos /* We require the user to provide a segment name. This is 28298b9484cSchristos unfortunate but I don't see any good choices here. */ 28398b9484cSchristos 28498b9484cSchristos if (segment_name == NULL) 28598b9484cSchristos { 28698b9484cSchristos *errmsg = "Mach-O file found but no segment name specified"; 28798b9484cSchristos *err = 0; 28898b9484cSchristos return NULL; 28998b9484cSchristos } 29098b9484cSchristos 29198b9484cSchristos if (strlen (segment_name) > MACH_O_NAME_LEN) 29298b9484cSchristos { 29398b9484cSchristos *errmsg = "Mach-O segment name too long"; 29498b9484cSchristos *err = 0; 29598b9484cSchristos return NULL; 29698b9484cSchristos } 29798b9484cSchristos 29898b9484cSchristos /* The 32-bit and 64-bit headers are similar enough that we can use 29998b9484cSchristos the same code. */ 30098b9484cSchristos 30198b9484cSchristos fetch_32 = (is_big_endian 30298b9484cSchristos ? simple_object_fetch_big_32 30398b9484cSchristos : simple_object_fetch_little_32); 30498b9484cSchristos 30598b9484cSchristos if (!simple_object_internal_read (descriptor, offset, buf, 30698b9484cSchristos (magic == MACH_O_MH_MAGIC 30798b9484cSchristos ? sizeof (struct mach_o_header_32) 30898b9484cSchristos : sizeof (struct mach_o_header_64)), 30998b9484cSchristos errmsg, err)) 31098b9484cSchristos return NULL; 31198b9484cSchristos 31298b9484cSchristos b = &buf[0]; 31398b9484cSchristos 31498b9484cSchristos filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype)); 31598b9484cSchristos if (filetype != MACH_O_MH_OBJECT) 31698b9484cSchristos { 31798b9484cSchristos *errmsg = "Mach-O file is not object file"; 31898b9484cSchristos *err = 0; 31998b9484cSchristos return NULL; 32098b9484cSchristos } 32198b9484cSchristos 32298b9484cSchristos omr = XNEW (struct simple_object_mach_o_read); 32398b9484cSchristos omr->segment_name = xstrdup (segment_name); 32498b9484cSchristos omr->magic = magic; 32598b9484cSchristos omr->is_big_endian = is_big_endian; 32698b9484cSchristos omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype)); 32798b9484cSchristos omr->cpusubtype = (*fetch_32) (b 32898b9484cSchristos + offsetof (struct mach_o_header_32, 32998b9484cSchristos cpusubtype)); 33098b9484cSchristos omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds)); 33198b9484cSchristos omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags)); 33298b9484cSchristos if (magic == MACH_O_MH_MAGIC) 33398b9484cSchristos omr->reserved = 0; 33498b9484cSchristos else 33598b9484cSchristos omr->reserved = (*fetch_32) (b 33698b9484cSchristos + offsetof (struct mach_o_header_64, 33798b9484cSchristos reserved)); 33898b9484cSchristos 33998b9484cSchristos return (void *) omr; 34098b9484cSchristos } 34198b9484cSchristos 34298b9484cSchristos /* Get the file offset and size from a section header. */ 34398b9484cSchristos 34498b9484cSchristos static void 34598b9484cSchristos simple_object_mach_o_section_info (int is_big_endian, int is_32, 34698b9484cSchristos const unsigned char *sechdr, off_t *offset, 34798b9484cSchristos size_t *size) 34898b9484cSchristos { 34998b9484cSchristos unsigned int (*fetch_32) (const unsigned char *); 35098b9484cSchristos ulong_type (*fetch_64) (const unsigned char *); 35198b9484cSchristos 35298b9484cSchristos fetch_32 = (is_big_endian 35398b9484cSchristos ? simple_object_fetch_big_32 35498b9484cSchristos : simple_object_fetch_little_32); 35598b9484cSchristos 35698b9484cSchristos fetch_64 = NULL; 35798b9484cSchristos #ifdef UNSIGNED_64BIT_TYPE 35898b9484cSchristos fetch_64 = (is_big_endian 35998b9484cSchristos ? simple_object_fetch_big_64 36098b9484cSchristos : simple_object_fetch_little_64); 36198b9484cSchristos #endif 36298b9484cSchristos 36398b9484cSchristos if (is_32) 36498b9484cSchristos { 36598b9484cSchristos *offset = fetch_32 (sechdr 36698b9484cSchristos + offsetof (struct mach_o_section_32, offset)); 36798b9484cSchristos *size = fetch_32 (sechdr 36898b9484cSchristos + offsetof (struct mach_o_section_32, size)); 36998b9484cSchristos } 37098b9484cSchristos else 37198b9484cSchristos { 37298b9484cSchristos *offset = fetch_32 (sechdr 37398b9484cSchristos + offsetof (struct mach_o_section_64, offset)); 37498b9484cSchristos *size = fetch_64 (sechdr 37598b9484cSchristos + offsetof (struct mach_o_section_64, size)); 37698b9484cSchristos } 37798b9484cSchristos } 37898b9484cSchristos 379a2e2270fSchristos /* Handle a segment in a Mach-O Object file. 380a2e2270fSchristos 381a2e2270fSchristos This will callback to the function pfn for each "section found" the meaning 382a2e2270fSchristos of which depends on gnu extensions to mach-o: 383a2e2270fSchristos 384a2e2270fSchristos If we find mach-o sections (with the segment name as specified) which also 385a2e2270fSchristos contain: a 'sects' wrapper, an index, and a name table, we expand this into 386a2e2270fSchristos as many sections as are specified in the index. In this case, there will 387a2e2270fSchristos be a callback for each of these. 388a2e2270fSchristos 389a2e2270fSchristos We will also allow an extension that permits long names (more than 16 390a2e2270fSchristos characters) to be used with mach-o. In this case, the section name has 391a2e2270fSchristos a specific format embedding an index into a name table, and the file must 392a2e2270fSchristos contain such name table. 393a2e2270fSchristos 394a2e2270fSchristos Return 1 if we should continue, 0 if the caller should return. */ 395a2e2270fSchristos 396a2e2270fSchristos #define SOMO_SECTS_PRESENT 0x01 397a2e2270fSchristos #define SOMO_INDEX_PRESENT 0x02 398a2e2270fSchristos #define SOMO_NAMES_PRESENT 0x04 399a2e2270fSchristos #define SOMO_LONGN_PRESENT 0x08 400a2e2270fSchristos #define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \ 401a2e2270fSchristos | SOMO_NAMES_PRESENT) 40298b9484cSchristos 40398b9484cSchristos static int 40498b9484cSchristos simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, 40598b9484cSchristos const unsigned char *segbuf, 40698b9484cSchristos int (*pfn) (void *, const char *, off_t offset, 40798b9484cSchristos off_t length), 40898b9484cSchristos void *data, 40998b9484cSchristos const char **errmsg, int *err) 41098b9484cSchristos { 41198b9484cSchristos struct simple_object_mach_o_read *omr = 41298b9484cSchristos (struct simple_object_mach_o_read *) sobj->data; 41398b9484cSchristos unsigned int (*fetch_32) (const unsigned char *); 41498b9484cSchristos int is_32; 41598b9484cSchristos size_t seghdrsize; 41698b9484cSchristos size_t sechdrsize; 41798b9484cSchristos size_t segname_offset; 41898b9484cSchristos size_t sectname_offset; 41998b9484cSchristos unsigned int nsects; 42098b9484cSchristos unsigned char *secdata; 42198b9484cSchristos unsigned int i; 422a2e2270fSchristos unsigned int gnu_sections_found; 42398b9484cSchristos unsigned int strtab_index; 424a2e2270fSchristos unsigned int index_index; 425a2e2270fSchristos unsigned int nametab_index; 426a2e2270fSchristos unsigned int sections_index; 42798b9484cSchristos char *strtab; 428a2e2270fSchristos char *nametab; 429a2e2270fSchristos unsigned char *index; 43098b9484cSchristos size_t strtab_size; 431a2e2270fSchristos size_t nametab_size; 432a2e2270fSchristos size_t index_size; 433a2e2270fSchristos unsigned int n_wrapped_sects; 434a2e2270fSchristos size_t wrapper_sect_size; 43503467a24Schristos off_t wrapper_sect_offset = 0; 43698b9484cSchristos 43798b9484cSchristos fetch_32 = (omr->is_big_endian 43898b9484cSchristos ? simple_object_fetch_big_32 43998b9484cSchristos : simple_object_fetch_little_32); 44098b9484cSchristos 44198b9484cSchristos is_32 = omr->magic == MACH_O_MH_MAGIC; 44298b9484cSchristos 44398b9484cSchristos if (is_32) 44498b9484cSchristos { 44598b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_32); 44698b9484cSchristos sechdrsize = sizeof (struct mach_o_section_32); 44798b9484cSchristos segname_offset = offsetof (struct mach_o_section_32, segname); 44898b9484cSchristos sectname_offset = offsetof (struct mach_o_section_32, sectname); 44998b9484cSchristos nsects = (*fetch_32) (segbuf 45098b9484cSchristos + offsetof (struct mach_o_segment_command_32, 45198b9484cSchristos nsects)); 45298b9484cSchristos } 45398b9484cSchristos else 45498b9484cSchristos { 45598b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_64); 45698b9484cSchristos sechdrsize = sizeof (struct mach_o_section_64); 45798b9484cSchristos segname_offset = offsetof (struct mach_o_section_64, segname); 45898b9484cSchristos sectname_offset = offsetof (struct mach_o_section_64, sectname); 45998b9484cSchristos nsects = (*fetch_32) (segbuf 46098b9484cSchristos + offsetof (struct mach_o_segment_command_64, 46198b9484cSchristos nsects)); 46298b9484cSchristos } 46398b9484cSchristos 464a2e2270fSchristos /* Fetch the section headers from the segment command. */ 465a2e2270fSchristos 46698b9484cSchristos secdata = XNEWVEC (unsigned char, nsects * sechdrsize); 46798b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, 46898b9484cSchristos secdata, nsects * sechdrsize, errmsg, err)) 46998b9484cSchristos { 47098b9484cSchristos XDELETEVEC (secdata); 47198b9484cSchristos return 0; 47298b9484cSchristos } 47398b9484cSchristos 474a2e2270fSchristos /* Scan for special sections that signal GNU extensions to the format. */ 47598b9484cSchristos 476a2e2270fSchristos gnu_sections_found = 0; 477a2e2270fSchristos index_index = nsects; 478a2e2270fSchristos sections_index = nsects; 479a2e2270fSchristos strtab_index = nsects; 480a2e2270fSchristos nametab_index = nsects; 48198b9484cSchristos for (i = 0; i < nsects; ++i) 48298b9484cSchristos { 48398b9484cSchristos size_t nameoff; 48498b9484cSchristos 48598b9484cSchristos nameoff = i * sechdrsize + segname_offset; 48698b9484cSchristos if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) 48798b9484cSchristos continue; 488a2e2270fSchristos 48998b9484cSchristos nameoff = i * sechdrsize + sectname_offset; 490a2e2270fSchristos if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0) 491a2e2270fSchristos { 492a2e2270fSchristos nametab_index = i; 493a2e2270fSchristos gnu_sections_found |= SOMO_NAMES_PRESENT; 494a2e2270fSchristos } 495a2e2270fSchristos else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0) 496a2e2270fSchristos { 497a2e2270fSchristos index_index = i; 498a2e2270fSchristos gnu_sections_found |= SOMO_INDEX_PRESENT; 499a2e2270fSchristos } 500a2e2270fSchristos else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0) 501a2e2270fSchristos { 502a2e2270fSchristos sections_index = i; 503a2e2270fSchristos gnu_sections_found |= SOMO_SECTS_PRESENT; 504a2e2270fSchristos } 505a2e2270fSchristos else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) 506a2e2270fSchristos { 507a2e2270fSchristos strtab_index = i; 508a2e2270fSchristos gnu_sections_found |= SOMO_LONGN_PRESENT; 509a2e2270fSchristos } 51098b9484cSchristos } 51198b9484cSchristos 512a2e2270fSchristos /* If any of the special wrapper section components is present, then 513a2e2270fSchristos they all should be. */ 514a2e2270fSchristos 515a2e2270fSchristos if ((gnu_sections_found & SOMO_WRAPPING) != 0) 51698b9484cSchristos { 517a2e2270fSchristos off_t nametab_offset; 518a2e2270fSchristos off_t index_offset; 519a2e2270fSchristos 520a2e2270fSchristos if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING) 521a2e2270fSchristos { 522a2e2270fSchristos *errmsg = "GNU Mach-o section wrapper: required section missing"; 523a2e2270fSchristos *err = 0; /* No useful errno. */ 524a2e2270fSchristos XDELETEVEC (secdata); 525a2e2270fSchristos return 0; 526a2e2270fSchristos } 527a2e2270fSchristos 528a2e2270fSchristos /* Fetch the name table. */ 529a2e2270fSchristos 530a2e2270fSchristos simple_object_mach_o_section_info (omr->is_big_endian, is_32, 531a2e2270fSchristos secdata + nametab_index * sechdrsize, 532a2e2270fSchristos &nametab_offset, &nametab_size); 533a2e2270fSchristos nametab = XNEWVEC (char, nametab_size); 534a2e2270fSchristos if (!simple_object_internal_read (sobj->descriptor, 535a2e2270fSchristos sobj->offset + nametab_offset, 536a2e2270fSchristos (unsigned char *) nametab, nametab_size, 537a2e2270fSchristos errmsg, err)) 538a2e2270fSchristos { 539a2e2270fSchristos XDELETEVEC (nametab); 540a2e2270fSchristos XDELETEVEC (secdata); 541a2e2270fSchristos return 0; 542a2e2270fSchristos } 543a2e2270fSchristos 544a2e2270fSchristos /* Fetch the index. */ 545a2e2270fSchristos 546a2e2270fSchristos simple_object_mach_o_section_info (omr->is_big_endian, is_32, 547a2e2270fSchristos secdata + index_index * sechdrsize, 548a2e2270fSchristos &index_offset, &index_size); 549a2e2270fSchristos index = XNEWVEC (unsigned char, index_size); 550a2e2270fSchristos if (!simple_object_internal_read (sobj->descriptor, 551a2e2270fSchristos sobj->offset + index_offset, 552a2e2270fSchristos index, index_size, 553a2e2270fSchristos errmsg, err)) 554a2e2270fSchristos { 555a2e2270fSchristos XDELETEVEC (index); 556a2e2270fSchristos XDELETEVEC (nametab); 557a2e2270fSchristos XDELETEVEC (secdata); 558a2e2270fSchristos return 0; 559a2e2270fSchristos } 560a2e2270fSchristos 561a2e2270fSchristos /* The index contains 4 unsigned ints per sub-section: 562a2e2270fSchristos sub-section offset/length, sub-section name/length. 563a2e2270fSchristos We fix this for both 32 and 64 bit mach-o for now, since 564a2e2270fSchristos other fields limit the maximum size of an object to 4G. */ 565a2e2270fSchristos n_wrapped_sects = index_size / 16; 566a2e2270fSchristos 567a2e2270fSchristos /* Get the parameters for the wrapper too. */ 568a2e2270fSchristos simple_object_mach_o_section_info (omr->is_big_endian, is_32, 569a2e2270fSchristos secdata + sections_index * sechdrsize, 570a2e2270fSchristos &wrapper_sect_offset, 571a2e2270fSchristos &wrapper_sect_size); 57298b9484cSchristos } 57398b9484cSchristos else 57498b9484cSchristos { 575a2e2270fSchristos index = NULL; 576a2e2270fSchristos index_size = 0; 577a2e2270fSchristos nametab = NULL; 578a2e2270fSchristos nametab_size = 0; 579a2e2270fSchristos n_wrapped_sects = 0; 580a2e2270fSchristos } 581a2e2270fSchristos 582a2e2270fSchristos /* If we have a long names section, fetch it. */ 583a2e2270fSchristos 584a2e2270fSchristos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) 585a2e2270fSchristos { 58698b9484cSchristos off_t strtab_offset; 58798b9484cSchristos 58898b9484cSchristos simple_object_mach_o_section_info (omr->is_big_endian, is_32, 58998b9484cSchristos secdata + strtab_index * sechdrsize, 59098b9484cSchristos &strtab_offset, &strtab_size); 59198b9484cSchristos strtab = XNEWVEC (char, strtab_size); 59298b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, 59398b9484cSchristos sobj->offset + strtab_offset, 59498b9484cSchristos (unsigned char *) strtab, strtab_size, 59598b9484cSchristos errmsg, err)) 59698b9484cSchristos { 59798b9484cSchristos XDELETEVEC (strtab); 598a2e2270fSchristos XDELETEVEC (index); 599a2e2270fSchristos XDELETEVEC (nametab); 60098b9484cSchristos XDELETEVEC (secdata); 60198b9484cSchristos return 0; 60298b9484cSchristos } 60398b9484cSchristos } 604a2e2270fSchristos else 605a2e2270fSchristos { 606a2e2270fSchristos strtab = NULL; 607a2e2270fSchristos strtab_size = 0; 608a2e2270fSchristos strtab_index = nsects; 609a2e2270fSchristos } 61098b9484cSchristos 61198b9484cSchristos /* Process the sections. */ 61298b9484cSchristos 61398b9484cSchristos for (i = 0; i < nsects; ++i) 61498b9484cSchristos { 61598b9484cSchristos const unsigned char *sechdr; 616a2e2270fSchristos char namebuf[MACH_O_NAME_LEN * 2 + 2]; 61798b9484cSchristos char *name; 61898b9484cSchristos off_t secoffset; 61998b9484cSchristos size_t secsize; 620a2e2270fSchristos int l; 62198b9484cSchristos 62298b9484cSchristos sechdr = secdata + i * sechdrsize; 62398b9484cSchristos 624a2e2270fSchristos /* We've already processed the long section names. */ 625a2e2270fSchristos 626a2e2270fSchristos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0 627a2e2270fSchristos && i == strtab_index) 628a2e2270fSchristos continue; 629a2e2270fSchristos 630a2e2270fSchristos /* We only act on the segment named. */ 631a2e2270fSchristos 63298b9484cSchristos if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) 63398b9484cSchristos continue; 63498b9484cSchristos 635a2e2270fSchristos /* Process sections associated with the wrapper. */ 636a2e2270fSchristos 637a2e2270fSchristos if ((gnu_sections_found & SOMO_WRAPPING) != 0) 638a2e2270fSchristos { 639a2e2270fSchristos if (i == nametab_index || i == index_index) 640a2e2270fSchristos continue; 641a2e2270fSchristos 642a2e2270fSchristos if (i == sections_index) 643a2e2270fSchristos { 644a2e2270fSchristos unsigned int j; 645a2e2270fSchristos for (j = 0; j < n_wrapped_sects; ++j) 646a2e2270fSchristos { 647a2e2270fSchristos unsigned int subsect_offset, subsect_length, name_offset; 648a2e2270fSchristos subsect_offset = (*fetch_32) (index + 16 * j); 649a2e2270fSchristos subsect_length = (*fetch_32) (index + 16 * j + 4); 650a2e2270fSchristos name_offset = (*fetch_32) (index + 16 * j + 8); 651a2e2270fSchristos /* We don't need the name_length yet. */ 652a2e2270fSchristos 653a2e2270fSchristos secoffset = wrapper_sect_offset + subsect_offset; 654a2e2270fSchristos secsize = subsect_length; 655a2e2270fSchristos name = nametab + name_offset; 656a2e2270fSchristos 657a2e2270fSchristos if (!(*pfn) (data, name, secoffset, secsize)) 658a2e2270fSchristos { 659a2e2270fSchristos *errmsg = NULL; 660a2e2270fSchristos *err = 0; 661a2e2270fSchristos XDELETEVEC (index); 662a2e2270fSchristos XDELETEVEC (nametab); 663a2e2270fSchristos XDELETEVEC (strtab); 664a2e2270fSchristos XDELETEVEC (secdata); 665a2e2270fSchristos return 0; 666a2e2270fSchristos } 667a2e2270fSchristos } 668a2e2270fSchristos continue; 669a2e2270fSchristos } 670a2e2270fSchristos } 671a2e2270fSchristos 672a2e2270fSchristos if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) 673a2e2270fSchristos { 67498b9484cSchristos memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); 67598b9484cSchristos namebuf[MACH_O_NAME_LEN] = '\0'; 67698b9484cSchristos 67798b9484cSchristos name = &namebuf[0]; 67898b9484cSchristos if (strtab != NULL && name[0] == '_' && name[1] == '_') 67998b9484cSchristos { 68098b9484cSchristos unsigned long stringoffset; 68198b9484cSchristos 68298b9484cSchristos if (sscanf (name + 2, "%08lX", &stringoffset) == 1) 68398b9484cSchristos { 68498b9484cSchristos if (stringoffset >= strtab_size) 68598b9484cSchristos { 68698b9484cSchristos *errmsg = "section name offset out of range"; 68798b9484cSchristos *err = 0; 688a2e2270fSchristos XDELETEVEC (index); 689a2e2270fSchristos XDELETEVEC (nametab); 69098b9484cSchristos XDELETEVEC (strtab); 69198b9484cSchristos XDELETEVEC (secdata); 69298b9484cSchristos return 0; 69398b9484cSchristos } 69498b9484cSchristos 69598b9484cSchristos name = strtab + stringoffset; 69698b9484cSchristos } 69798b9484cSchristos } 698a2e2270fSchristos } 699a2e2270fSchristos else 700a2e2270fSchristos { 701a2e2270fSchristos /* Otherwise, make a name like __segment,__section as per the 702a2e2270fSchristos convention in mach-o asm. */ 703a2e2270fSchristos name = &namebuf[0]; 704a2e2270fSchristos memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN); 705a2e2270fSchristos namebuf[MACH_O_NAME_LEN] = '\0'; 706a2e2270fSchristos l = strlen (namebuf); 707a2e2270fSchristos namebuf[l] = ','; 708a2e2270fSchristos memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset, 709a2e2270fSchristos MACH_O_NAME_LEN); 710a2e2270fSchristos namebuf[l + 1 + MACH_O_NAME_LEN] = '\0'; 711a2e2270fSchristos } 71298b9484cSchristos 71398b9484cSchristos simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, 71498b9484cSchristos &secoffset, &secsize); 71598b9484cSchristos 71698b9484cSchristos if (!(*pfn) (data, name, secoffset, secsize)) 71798b9484cSchristos { 71898b9484cSchristos *errmsg = NULL; 71998b9484cSchristos *err = 0; 720a2e2270fSchristos XDELETEVEC (index); 721a2e2270fSchristos XDELETEVEC (nametab); 72298b9484cSchristos XDELETEVEC (strtab); 72398b9484cSchristos XDELETEVEC (secdata); 72498b9484cSchristos return 0; 72598b9484cSchristos } 72698b9484cSchristos } 72798b9484cSchristos 728a2e2270fSchristos XDELETEVEC (index); 729a2e2270fSchristos XDELETEVEC (nametab); 73098b9484cSchristos XDELETEVEC (strtab); 73198b9484cSchristos XDELETEVEC (secdata); 73298b9484cSchristos 73398b9484cSchristos return 1; 73498b9484cSchristos } 73598b9484cSchristos 73698b9484cSchristos /* Find all sections in a Mach-O file. */ 73798b9484cSchristos 73898b9484cSchristos static const char * 73998b9484cSchristos simple_object_mach_o_find_sections (simple_object_read *sobj, 74098b9484cSchristos int (*pfn) (void *, const char *, 74198b9484cSchristos off_t offset, off_t length), 74298b9484cSchristos void *data, 74398b9484cSchristos int *err) 74498b9484cSchristos { 74598b9484cSchristos struct simple_object_mach_o_read *omr = 74698b9484cSchristos (struct simple_object_mach_o_read *) sobj->data; 74798b9484cSchristos off_t offset; 74898b9484cSchristos size_t seghdrsize; 74998b9484cSchristos unsigned int (*fetch_32) (const unsigned char *); 75098b9484cSchristos const char *errmsg; 75198b9484cSchristos unsigned int i; 75298b9484cSchristos 75398b9484cSchristos if (omr->magic == MACH_O_MH_MAGIC) 75498b9484cSchristos { 75598b9484cSchristos offset = sizeof (struct mach_o_header_32); 75698b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_32); 75798b9484cSchristos } 75898b9484cSchristos else 75998b9484cSchristos { 76098b9484cSchristos offset = sizeof (struct mach_o_header_64); 76198b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_64); 76298b9484cSchristos } 76398b9484cSchristos 76498b9484cSchristos fetch_32 = (omr->is_big_endian 76598b9484cSchristos ? simple_object_fetch_big_32 76698b9484cSchristos : simple_object_fetch_little_32); 76798b9484cSchristos 76898b9484cSchristos for (i = 0; i < omr->ncmds; ++i) 76998b9484cSchristos { 77098b9484cSchristos unsigned char loadbuf[sizeof (struct mach_o_load_command)]; 77198b9484cSchristos unsigned int cmd; 77298b9484cSchristos unsigned int cmdsize; 77398b9484cSchristos 77498b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, 77598b9484cSchristos sobj->offset + offset, 77698b9484cSchristos loadbuf, 77798b9484cSchristos sizeof (struct mach_o_load_command), 77898b9484cSchristos &errmsg, err)) 77998b9484cSchristos return errmsg; 78098b9484cSchristos 78198b9484cSchristos cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd)); 78298b9484cSchristos cmdsize = (*fetch_32) (loadbuf 78398b9484cSchristos + offsetof (struct mach_o_load_command, cmdsize)); 78498b9484cSchristos 78598b9484cSchristos if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64) 78698b9484cSchristos { 78798b9484cSchristos unsigned char segbuf[sizeof (struct mach_o_segment_command_64)]; 78898b9484cSchristos int r; 78998b9484cSchristos 79098b9484cSchristos if (!simple_object_internal_read (sobj->descriptor, 79198b9484cSchristos sobj->offset + offset, 79298b9484cSchristos segbuf, seghdrsize, &errmsg, err)) 79398b9484cSchristos return errmsg; 79498b9484cSchristos 79598b9484cSchristos r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn, 79698b9484cSchristos data, &errmsg, err); 79798b9484cSchristos if (!r) 79898b9484cSchristos return errmsg; 79998b9484cSchristos } 80098b9484cSchristos 80198b9484cSchristos offset += cmdsize; 80298b9484cSchristos } 80398b9484cSchristos 80498b9484cSchristos return NULL; 80598b9484cSchristos } 80698b9484cSchristos 80798b9484cSchristos /* Fetch the attributes for an simple_object_read. */ 80898b9484cSchristos 80998b9484cSchristos static void * 81098b9484cSchristos simple_object_mach_o_fetch_attributes (simple_object_read *sobj, 81198b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 81298b9484cSchristos int *err ATTRIBUTE_UNUSED) 81398b9484cSchristos { 81498b9484cSchristos struct simple_object_mach_o_read *omr = 81598b9484cSchristos (struct simple_object_mach_o_read *) sobj->data; 81698b9484cSchristos struct simple_object_mach_o_attributes *ret; 81798b9484cSchristos 81898b9484cSchristos ret = XNEW (struct simple_object_mach_o_attributes); 81998b9484cSchristos ret->magic = omr->magic; 82098b9484cSchristos ret->is_big_endian = omr->is_big_endian; 82198b9484cSchristos ret->cputype = omr->cputype; 82298b9484cSchristos ret->cpusubtype = omr->cpusubtype; 82398b9484cSchristos ret->flags = omr->flags; 82498b9484cSchristos ret->reserved = omr->reserved; 82598b9484cSchristos return ret; 82698b9484cSchristos } 82798b9484cSchristos 82898b9484cSchristos /* Release the private data for an simple_object_read. */ 82998b9484cSchristos 83098b9484cSchristos static void 83198b9484cSchristos simple_object_mach_o_release_read (void *data) 83298b9484cSchristos { 83398b9484cSchristos struct simple_object_mach_o_read *omr = 83498b9484cSchristos (struct simple_object_mach_o_read *) data; 83598b9484cSchristos 83698b9484cSchristos free (omr->segment_name); 83798b9484cSchristos XDELETE (omr); 83898b9484cSchristos } 83998b9484cSchristos 84098b9484cSchristos /* Compare two attributes structures. */ 84198b9484cSchristos 84298b9484cSchristos static const char * 84398b9484cSchristos simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err) 84498b9484cSchristos { 84598b9484cSchristos struct simple_object_mach_o_attributes *to = 84698b9484cSchristos (struct simple_object_mach_o_attributes *) todata; 84798b9484cSchristos struct simple_object_mach_o_attributes *from = 84898b9484cSchristos (struct simple_object_mach_o_attributes *) fromdata; 84998b9484cSchristos 85098b9484cSchristos if (to->magic != from->magic 85198b9484cSchristos || to->is_big_endian != from->is_big_endian 85298b9484cSchristos || to->cputype != from->cputype) 85398b9484cSchristos { 85498b9484cSchristos *err = 0; 85598b9484cSchristos return "Mach-O object format mismatch"; 85698b9484cSchristos } 85798b9484cSchristos return NULL; 85898b9484cSchristos } 85998b9484cSchristos 86098b9484cSchristos /* Release the private data for an attributes structure. */ 86198b9484cSchristos 86298b9484cSchristos static void 86398b9484cSchristos simple_object_mach_o_release_attributes (void *data) 86498b9484cSchristos { 86598b9484cSchristos XDELETE (data); 86698b9484cSchristos } 86798b9484cSchristos 86898b9484cSchristos /* Prepare to write out a file. */ 86998b9484cSchristos 87098b9484cSchristos static void * 87198b9484cSchristos simple_object_mach_o_start_write (void *attributes_data, 87298b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 87398b9484cSchristos int *err ATTRIBUTE_UNUSED) 87498b9484cSchristos { 87598b9484cSchristos struct simple_object_mach_o_attributes *attrs = 87698b9484cSchristos (struct simple_object_mach_o_attributes *) attributes_data; 87798b9484cSchristos struct simple_object_mach_o_attributes *ret; 87898b9484cSchristos 87998b9484cSchristos /* We're just going to record the attributes, but we need to make a 88098b9484cSchristos copy because the user may delete them. */ 88198b9484cSchristos ret = XNEW (struct simple_object_mach_o_attributes); 88298b9484cSchristos *ret = *attrs; 88398b9484cSchristos return ret; 88498b9484cSchristos } 88598b9484cSchristos 88698b9484cSchristos /* Write out the header of a Mach-O file. */ 88798b9484cSchristos 88898b9484cSchristos static int 88998b9484cSchristos simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor, 89098b9484cSchristos size_t nsects, const char **errmsg, 89198b9484cSchristos int *err) 89298b9484cSchristos { 89398b9484cSchristos struct simple_object_mach_o_attributes *attrs = 89498b9484cSchristos (struct simple_object_mach_o_attributes *) sobj->data; 89598b9484cSchristos void (*set_32) (unsigned char *, unsigned int); 89698b9484cSchristos unsigned char hdrbuf[sizeof (struct mach_o_header_64)]; 89798b9484cSchristos unsigned char *hdr; 89898b9484cSchristos size_t wrsize; 89998b9484cSchristos 90098b9484cSchristos set_32 = (attrs->is_big_endian 90198b9484cSchristos ? simple_object_set_big_32 90298b9484cSchristos : simple_object_set_little_32); 90398b9484cSchristos 90498b9484cSchristos memset (hdrbuf, 0, sizeof hdrbuf); 90598b9484cSchristos 90698b9484cSchristos /* The 32-bit and 64-bit headers start out the same. */ 90798b9484cSchristos 90898b9484cSchristos hdr = &hdrbuf[0]; 90998b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic); 91098b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype); 91198b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype), 91298b9484cSchristos attrs->cpusubtype); 91398b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT); 91498b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1); 91598b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags); 91698b9484cSchristos if (attrs->magic == MACH_O_MH_MAGIC) 91798b9484cSchristos { 91898b9484cSchristos wrsize = sizeof (struct mach_o_header_32); 91998b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds), 92098b9484cSchristos (sizeof (struct mach_o_segment_command_32) 92198b9484cSchristos + nsects * sizeof (struct mach_o_section_32))); 92298b9484cSchristos } 92398b9484cSchristos else 92498b9484cSchristos { 92598b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds), 92698b9484cSchristos (sizeof (struct mach_o_segment_command_64) 92798b9484cSchristos + nsects * sizeof (struct mach_o_section_64))); 92898b9484cSchristos set_32 (hdr + offsetof (struct mach_o_header_64, reserved), 92998b9484cSchristos attrs->reserved); 93098b9484cSchristos wrsize = sizeof (struct mach_o_header_64); 93198b9484cSchristos } 93298b9484cSchristos 93398b9484cSchristos return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize, 93498b9484cSchristos errmsg, err); 93598b9484cSchristos } 93698b9484cSchristos 93798b9484cSchristos /* Write a Mach-O section header. */ 93898b9484cSchristos 93998b9484cSchristos static int 94098b9484cSchristos simple_object_mach_o_write_section_header (simple_object_write *sobj, 94198b9484cSchristos int descriptor, 94298b9484cSchristos size_t sechdr_offset, 943a2e2270fSchristos const char *name, const char *segn, 944a2e2270fSchristos size_t secaddr, size_t secsize, 945a2e2270fSchristos size_t offset, unsigned int align, 94698b9484cSchristos const char **errmsg, int *err) 94798b9484cSchristos { 94898b9484cSchristos struct simple_object_mach_o_attributes *attrs = 94998b9484cSchristos (struct simple_object_mach_o_attributes *) sobj->data; 95098b9484cSchristos void (*set_32) (unsigned char *, unsigned int); 95198b9484cSchristos unsigned char hdrbuf[sizeof (struct mach_o_section_64)]; 95298b9484cSchristos unsigned char *hdr; 95398b9484cSchristos size_t sechdrsize; 95498b9484cSchristos 95598b9484cSchristos set_32 = (attrs->is_big_endian 95698b9484cSchristos ? simple_object_set_big_32 95798b9484cSchristos : simple_object_set_little_32); 95898b9484cSchristos 95998b9484cSchristos memset (hdrbuf, 0, sizeof hdrbuf); 96098b9484cSchristos 96198b9484cSchristos hdr = &hdrbuf[0]; 96298b9484cSchristos if (attrs->magic == MACH_O_MH_MAGIC) 96398b9484cSchristos { 96498b9484cSchristos strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), 96598b9484cSchristos name, MACH_O_NAME_LEN); 96698b9484cSchristos strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), 967a2e2270fSchristos segn, MACH_O_NAME_LEN); 96898b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); 96998b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); 97098b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); 97198b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_32, align), align); 97298b9484cSchristos /* reloff left as zero. */ 97398b9484cSchristos /* nreloc left as zero. */ 97498b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_32, flags), 97598b9484cSchristos MACH_O_S_ATTR_DEBUG); 97698b9484cSchristos /* reserved1 left as zero. */ 97798b9484cSchristos /* reserved2 left as zero. */ 97898b9484cSchristos sechdrsize = sizeof (struct mach_o_section_32); 97998b9484cSchristos } 98098b9484cSchristos else 98198b9484cSchristos { 98298b9484cSchristos #ifdef UNSIGNED_64BIT_TYPE 98398b9484cSchristos void (*set_64) (unsigned char *, ulong_type); 98498b9484cSchristos 98598b9484cSchristos set_64 = (attrs->is_big_endian 98698b9484cSchristos ? simple_object_set_big_64 98798b9484cSchristos : simple_object_set_little_64); 98898b9484cSchristos 98998b9484cSchristos strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), 99098b9484cSchristos name, MACH_O_NAME_LEN); 99198b9484cSchristos strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), 992a2e2270fSchristos segn, MACH_O_NAME_LEN); 99398b9484cSchristos set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); 99498b9484cSchristos set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); 99598b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); 99698b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_64, align), align); 99798b9484cSchristos /* reloff left as zero. */ 99898b9484cSchristos /* nreloc left as zero. */ 99998b9484cSchristos set_32 (hdr + offsetof (struct mach_o_section_64, flags), 100098b9484cSchristos MACH_O_S_ATTR_DEBUG); 100198b9484cSchristos /* reserved1 left as zero. */ 100298b9484cSchristos /* reserved2 left as zero. */ 100398b9484cSchristos /* reserved3 left as zero. */ 100498b9484cSchristos #endif 100598b9484cSchristos sechdrsize = sizeof (struct mach_o_section_64); 100698b9484cSchristos } 100798b9484cSchristos 100898b9484cSchristos return simple_object_internal_write (descriptor, sechdr_offset, hdr, 100998b9484cSchristos sechdrsize, errmsg, err); 101098b9484cSchristos } 101198b9484cSchristos 1012a2e2270fSchristos /* Write out the single (anonymous) segment containing the sections of a Mach-O 1013a2e2270fSchristos Object file. 1014a2e2270fSchristos 1015a2e2270fSchristos As a GNU extension to mach-o, when the caller specifies a segment name in 1016a2e2270fSchristos sobj->segment_name, all the sections passed will be output under a single 1017a2e2270fSchristos mach-o section header. The caller's sections are indexed within this 1018a2e2270fSchristos 'wrapper' section by a table stored in a second mach-o section. Finally, 1019a2e2270fSchristos arbitrary length section names are permitted by the extension and these are 1020a2e2270fSchristos stored in a table in a third mach-o section. 1021a2e2270fSchristos 1022a2e2270fSchristos Note that this is only likely to make any sense for the __GNU_LTO segment 1023a2e2270fSchristos at present. 1024a2e2270fSchristos 1025a2e2270fSchristos If the wrapper extension is not in force, we assume that the section name 1026a2e2270fSchristos is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */ 102798b9484cSchristos 102898b9484cSchristos static int 102998b9484cSchristos simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, 1030a2e2270fSchristos size_t *nsects, const char **errmsg, 103198b9484cSchristos int *err) 103298b9484cSchristos { 103398b9484cSchristos struct simple_object_mach_o_attributes *attrs = 103498b9484cSchristos (struct simple_object_mach_o_attributes *) sobj->data; 103598b9484cSchristos void (*set_32) (unsigned char *, unsigned int); 103698b9484cSchristos size_t hdrsize; 103798b9484cSchristos size_t seghdrsize; 103898b9484cSchristos size_t sechdrsize; 103998b9484cSchristos size_t cmdsize; 104098b9484cSchristos size_t offset; 104198b9484cSchristos size_t sechdr_offset; 104298b9484cSchristos size_t secaddr; 104398b9484cSchristos unsigned int name_offset; 104498b9484cSchristos simple_object_write_section *section; 104598b9484cSchristos unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; 104698b9484cSchristos unsigned char *hdr; 1047a2e2270fSchristos size_t nsects_in; 1048a2e2270fSchristos unsigned int *index; 1049a2e2270fSchristos char *snames; 1050a2e2270fSchristos unsigned int sect; 105198b9484cSchristos 105298b9484cSchristos set_32 = (attrs->is_big_endian 105398b9484cSchristos ? simple_object_set_big_32 105498b9484cSchristos : simple_object_set_little_32); 105598b9484cSchristos 105698b9484cSchristos /* Write out the sections first. */ 105798b9484cSchristos 105898b9484cSchristos if (attrs->magic == MACH_O_MH_MAGIC) 105998b9484cSchristos { 106098b9484cSchristos hdrsize = sizeof (struct mach_o_header_32); 106198b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_32); 106298b9484cSchristos sechdrsize = sizeof (struct mach_o_section_32); 106398b9484cSchristos } 106498b9484cSchristos else 106598b9484cSchristos { 106698b9484cSchristos hdrsize = sizeof (struct mach_o_header_64); 106798b9484cSchristos seghdrsize = sizeof (struct mach_o_segment_command_64); 106898b9484cSchristos sechdrsize = sizeof (struct mach_o_section_64); 106998b9484cSchristos } 107098b9484cSchristos 107198b9484cSchristos name_offset = 0; 1072a2e2270fSchristos *nsects = nsects_in = 0; 1073a2e2270fSchristos 1074a2e2270fSchristos /* Count the number of sections we start with. */ 107598b9484cSchristos 107698b9484cSchristos for (section = sobj->sections; section != NULL; section = section->next) 1077a2e2270fSchristos nsects_in++; 1078a2e2270fSchristos 1079a2e2270fSchristos if (sobj->segment_name != NULL) 1080a2e2270fSchristos { 1081a2e2270fSchristos /* We will only write 3 sections: wrapped data, index and names. */ 1082a2e2270fSchristos 1083a2e2270fSchristos *nsects = 3; 1084a2e2270fSchristos 1085a2e2270fSchristos /* The index has four entries per wrapped section: 1086a2e2270fSchristos Section Offset, length, Name offset, length. 1087a2e2270fSchristos Where the offsets are based at the start of the wrapper and name 1088a2e2270fSchristos sections respectively. 1089a2e2270fSchristos The values are stored as 32 bit int for both 32 and 64 bit mach-o 1090a2e2270fSchristos since the size of a mach-o MH_OBJECT cannot exceed 4G owing to 1091a2e2270fSchristos other constraints. */ 1092a2e2270fSchristos 1093a2e2270fSchristos index = XNEWVEC (unsigned int, nsects_in * 4); 1094a2e2270fSchristos 1095a2e2270fSchristos /* We now need to figure out the size of the names section. This just 1096a2e2270fSchristos stores the names as null-terminated c strings, packed without any 1097a2e2270fSchristos alignment padding. */ 1098a2e2270fSchristos 1099a2e2270fSchristos for (section = sobj->sections, sect = 0; section != NULL; 1100a2e2270fSchristos section = section->next, sect++) 1101a2e2270fSchristos { 1102a2e2270fSchristos index[sect*4+2] = name_offset; 1103a2e2270fSchristos index[sect*4+3] = strlen (section->name) + 1; 1104a2e2270fSchristos name_offset += strlen (section->name) + 1; 1105a2e2270fSchristos } 1106a2e2270fSchristos snames = XNEWVEC (char, name_offset); 1107a2e2270fSchristos } 1108a2e2270fSchristos else 1109a2e2270fSchristos { 1110a2e2270fSchristos *nsects = nsects_in; 1111a2e2270fSchristos index = NULL; 1112a2e2270fSchristos snames = NULL; 1113a2e2270fSchristos } 1114a2e2270fSchristos 1115a2e2270fSchristos sechdr_offset = hdrsize + seghdrsize; 1116a2e2270fSchristos cmdsize = seghdrsize + *nsects * sechdrsize; 1117a2e2270fSchristos offset = hdrsize + cmdsize; 1118a2e2270fSchristos secaddr = 0; 1119a2e2270fSchristos 1120a2e2270fSchristos for (section = sobj->sections, sect = 0; 1121a2e2270fSchristos section != NULL; section = section->next, sect++) 112298b9484cSchristos { 112398b9484cSchristos size_t mask; 112498b9484cSchristos size_t new_offset; 112598b9484cSchristos size_t secsize; 112698b9484cSchristos struct simple_object_write_section_buffer *buffer; 112798b9484cSchristos 112898b9484cSchristos mask = (1U << section->align) - 1; 112998b9484cSchristos new_offset = offset + mask; 113098b9484cSchristos new_offset &= ~ mask; 113198b9484cSchristos while (new_offset > offset) 113298b9484cSchristos { 113398b9484cSchristos unsigned char zeroes[16]; 113498b9484cSchristos size_t write; 113598b9484cSchristos 113698b9484cSchristos memset (zeroes, 0, sizeof zeroes); 113798b9484cSchristos write = new_offset - offset; 113898b9484cSchristos if (write > sizeof zeroes) 113998b9484cSchristos write = sizeof zeroes; 114098b9484cSchristos if (!simple_object_internal_write (descriptor, offset, zeroes, write, 114198b9484cSchristos errmsg, err)) 114298b9484cSchristos return 0; 114398b9484cSchristos offset += write; 114498b9484cSchristos } 114598b9484cSchristos 114698b9484cSchristos secsize = 0; 114798b9484cSchristos for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) 114898b9484cSchristos { 114998b9484cSchristos if (!simple_object_internal_write (descriptor, offset + secsize, 115098b9484cSchristos ((const unsigned char *) 115198b9484cSchristos buffer->buffer), 115298b9484cSchristos buffer->size, errmsg, err)) 115398b9484cSchristos return 0; 115498b9484cSchristos secsize += buffer->size; 115598b9484cSchristos } 115698b9484cSchristos 1157a2e2270fSchristos if (sobj->segment_name != NULL) 1158a2e2270fSchristos { 1159a2e2270fSchristos index[sect*4+0] = (unsigned int) offset; 1160a2e2270fSchristos index[sect*4+1] = secsize; 1161a2e2270fSchristos /* Stash the section name in our table. */ 1162a2e2270fSchristos memcpy (snames + index[sect * 4 + 2], section->name, 1163a2e2270fSchristos index[sect * 4 + 3]); 116498b9484cSchristos } 1165a2e2270fSchristos else 1166a2e2270fSchristos { 1167a2e2270fSchristos char namebuf[MACH_O_NAME_LEN + 1]; 1168a2e2270fSchristos char segnbuf[MACH_O_NAME_LEN + 1]; 1169a2e2270fSchristos char *comma; 117098b9484cSchristos 1171a2e2270fSchristos /* Try to extract segment,section from the input name. */ 1172a2e2270fSchristos 1173a2e2270fSchristos memset (namebuf, 0, sizeof namebuf); 1174a2e2270fSchristos memset (segnbuf, 0, sizeof segnbuf); 1175a2e2270fSchristos comma = strchr (section->name, ','); 1176a2e2270fSchristos if (comma != NULL) 1177a2e2270fSchristos { 1178a2e2270fSchristos int len = comma - section->name; 1179a2e2270fSchristos len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len; 1180a2e2270fSchristos strncpy (namebuf, section->name, len); 1181a2e2270fSchristos strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN); 1182a2e2270fSchristos } 1183a2e2270fSchristos else /* just try to copy the name, leave segment blank. */ 1184a2e2270fSchristos strncpy (namebuf, section->name, MACH_O_NAME_LEN); 118598b9484cSchristos 118698b9484cSchristos if (!simple_object_mach_o_write_section_header (sobj, descriptor, 118798b9484cSchristos sechdr_offset, 1188a2e2270fSchristos namebuf, segnbuf, 1189a2e2270fSchristos secaddr, secsize, 1190a2e2270fSchristos offset, 1191a2e2270fSchristos section->align, 1192a2e2270fSchristos errmsg, err)) 1193a2e2270fSchristos return 0; 1194a2e2270fSchristos sechdr_offset += sechdrsize; 1195a2e2270fSchristos } 1196a2e2270fSchristos 1197a2e2270fSchristos offset += secsize; 1198a2e2270fSchristos secaddr += secsize; 1199a2e2270fSchristos } 1200a2e2270fSchristos 1201a2e2270fSchristos if (sobj->segment_name != NULL) 1202a2e2270fSchristos { 1203a2e2270fSchristos size_t secsize; 1204a2e2270fSchristos unsigned int i; 1205a2e2270fSchristos 1206a2e2270fSchristos /* Write the section header for the wrapper. */ 1207a2e2270fSchristos /* Account for any initial aligment - which becomes the alignment for this 1208a2e2270fSchristos created section. */ 1209a2e2270fSchristos 1210a2e2270fSchristos secsize = (offset - index[0]); 1211a2e2270fSchristos if (!simple_object_mach_o_write_section_header (sobj, descriptor, 1212a2e2270fSchristos sechdr_offset, 1213a2e2270fSchristos GNU_WRAPPER_SECTS, 1214a2e2270fSchristos sobj->segment_name, 1215a2e2270fSchristos 0 /*secaddr*/, 1216a2e2270fSchristos secsize, index[0], 1217a2e2270fSchristos sobj->sections->align, 121898b9484cSchristos errmsg, err)) 121998b9484cSchristos return 0; 122098b9484cSchristos 1221a2e2270fSchristos /* Subtract the wrapper section start from the begining of each sub 1222a2e2270fSchristos section. */ 122398b9484cSchristos 1224a2e2270fSchristos for (i = 1; i < nsects_in; ++i) 1225a2e2270fSchristos index[4 * i] -= index[0]; 1226a2e2270fSchristos index[0] = 0; 1227a2e2270fSchristos 12284b169a6bSchristos /* Swap the indices, if required. */ 12294b169a6bSchristos 12304b169a6bSchristos for (i = 0; i < (nsects_in * 4); ++i) 12314b169a6bSchristos set_32 ((unsigned char *) &index[i], index[i]); 12324b169a6bSchristos 1233a2e2270fSchristos sechdr_offset += sechdrsize; 1234a2e2270fSchristos 1235a2e2270fSchristos /* Write out the section names. 1236a2e2270fSchristos ... the header ... 1237a2e2270fSchristos name_offset contains the length of the section. It is not aligned. */ 1238a2e2270fSchristos 1239a2e2270fSchristos if (!simple_object_mach_o_write_section_header (sobj, descriptor, 1240a2e2270fSchristos sechdr_offset, 1241a2e2270fSchristos GNU_WRAPPER_NAMES, 1242a2e2270fSchristos sobj->segment_name, 1243a2e2270fSchristos 0 /*secaddr*/, 1244a2e2270fSchristos name_offset, 1245a2e2270fSchristos offset, 1246a2e2270fSchristos 0, errmsg, err)) 124798b9484cSchristos return 0; 1248a2e2270fSchristos 1249a2e2270fSchristos /* ... and the content.. */ 1250a2e2270fSchristos if (!simple_object_internal_write (descriptor, offset, 1251a2e2270fSchristos (const unsigned char *) snames, 1252a2e2270fSchristos name_offset, errmsg, err)) 1253a2e2270fSchristos return 0; 1254a2e2270fSchristos 1255a2e2270fSchristos sechdr_offset += sechdrsize; 1256a2e2270fSchristos secaddr += name_offset; 1257a2e2270fSchristos offset += name_offset; 1258a2e2270fSchristos 1259a2e2270fSchristos /* Now do the index, we'll align this to 4 bytes although the read code 1260a2e2270fSchristos will handle unaligned. */ 1261a2e2270fSchristos 1262a2e2270fSchristos offset += 3; 1263a2e2270fSchristos offset &= ~0x03; 1264a2e2270fSchristos if (!simple_object_mach_o_write_section_header (sobj, descriptor, 1265a2e2270fSchristos sechdr_offset, 1266a2e2270fSchristos GNU_WRAPPER_INDEX, 1267a2e2270fSchristos sobj->segment_name, 1268a2e2270fSchristos 0 /*secaddr*/, 1269a2e2270fSchristos nsects_in * 16, 1270a2e2270fSchristos offset, 1271a2e2270fSchristos 2, errmsg, err)) 1272a2e2270fSchristos return 0; 1273a2e2270fSchristos 1274a2e2270fSchristos /* ... and the content.. */ 1275a2e2270fSchristos if (!simple_object_internal_write (descriptor, offset, 1276a2e2270fSchristos (const unsigned char *) index, 1277a2e2270fSchristos nsects_in*16, errmsg, err)) 1278a2e2270fSchristos return 0; 1279a2e2270fSchristos 1280a2e2270fSchristos XDELETEVEC (index); 1281a2e2270fSchristos XDELETEVEC (snames); 128298b9484cSchristos } 128398b9484cSchristos 128498b9484cSchristos /* Write out the segment header. */ 128598b9484cSchristos 128698b9484cSchristos memset (hdrbuf, 0, sizeof hdrbuf); 128798b9484cSchristos 128898b9484cSchristos hdr = &hdrbuf[0]; 128998b9484cSchristos if (attrs->magic == MACH_O_MH_MAGIC) 129098b9484cSchristos { 129198b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), 129298b9484cSchristos MACH_O_LC_SEGMENT); 129398b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), 129498b9484cSchristos cmdsize); 1295a2e2270fSchristos /* MH_OBJECTS have a single, anonymous, segment - so the segment name 1296a2e2270fSchristos is left empty. */ 129798b9484cSchristos /* vmaddr left as zero. */ 129898b9484cSchristos /* vmsize left as zero. */ 129998b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), 130098b9484cSchristos hdrsize + cmdsize); 130198b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), 130298b9484cSchristos offset - (hdrsize + cmdsize)); 130398b9484cSchristos /* maxprot left as zero. */ 130498b9484cSchristos /* initprot left as zero. */ 130598b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), 1306a2e2270fSchristos *nsects); 130798b9484cSchristos /* flags left as zero. */ 130898b9484cSchristos } 130998b9484cSchristos else 131098b9484cSchristos { 131198b9484cSchristos #ifdef UNSIGNED_64BIT_TYPE 131298b9484cSchristos void (*set_64) (unsigned char *, ulong_type); 131398b9484cSchristos 131498b9484cSchristos set_64 = (attrs->is_big_endian 131598b9484cSchristos ? simple_object_set_big_64 131698b9484cSchristos : simple_object_set_little_64); 131798b9484cSchristos 131898b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), 131998b9484cSchristos MACH_O_LC_SEGMENT); 132098b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), 132198b9484cSchristos cmdsize); 1322a2e2270fSchristos /* MH_OBJECTS have a single, anonymous, segment - so the segment name 1323a2e2270fSchristos is left empty. */ 132498b9484cSchristos /* vmaddr left as zero. */ 132598b9484cSchristos /* vmsize left as zero. */ 132698b9484cSchristos set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), 132798b9484cSchristos hdrsize + cmdsize); 132898b9484cSchristos set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), 132998b9484cSchristos offset - (hdrsize + cmdsize)); 133098b9484cSchristos /* maxprot left as zero. */ 133198b9484cSchristos /* initprot left as zero. */ 133298b9484cSchristos set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), 1333a2e2270fSchristos *nsects); 133498b9484cSchristos /* flags left as zero. */ 133598b9484cSchristos #endif 133698b9484cSchristos } 133798b9484cSchristos 133898b9484cSchristos return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, 133998b9484cSchristos errmsg, err); 134098b9484cSchristos } 134198b9484cSchristos 134298b9484cSchristos /* Write out a complete Mach-O file. */ 134398b9484cSchristos 134498b9484cSchristos static const char * 134598b9484cSchristos simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, 134698b9484cSchristos int *err) 134798b9484cSchristos { 1348a2e2270fSchristos size_t nsects = 0; 134998b9484cSchristos const char *errmsg; 135098b9484cSchristos 1351a2e2270fSchristos if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects, 135298b9484cSchristos &errmsg, err)) 135398b9484cSchristos return errmsg; 135498b9484cSchristos 1355a2e2270fSchristos if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, 135698b9484cSchristos &errmsg, err)) 135798b9484cSchristos return errmsg; 135898b9484cSchristos 135998b9484cSchristos return NULL; 136098b9484cSchristos } 136198b9484cSchristos 136298b9484cSchristos /* Release the private data for an simple_object_write structure. */ 136398b9484cSchristos 136498b9484cSchristos static void 136598b9484cSchristos simple_object_mach_o_release_write (void *data) 136698b9484cSchristos { 136798b9484cSchristos XDELETE (data); 136898b9484cSchristos } 136998b9484cSchristos 137098b9484cSchristos /* The Mach-O functions. */ 137198b9484cSchristos 137298b9484cSchristos const struct simple_object_functions simple_object_mach_o_functions = 137398b9484cSchristos { 137498b9484cSchristos simple_object_mach_o_match, 137598b9484cSchristos simple_object_mach_o_find_sections, 137698b9484cSchristos simple_object_mach_o_fetch_attributes, 137798b9484cSchristos simple_object_mach_o_release_read, 137898b9484cSchristos simple_object_mach_o_attributes_merge, 137998b9484cSchristos simple_object_mach_o_release_attributes, 138098b9484cSchristos simple_object_mach_o_start_write, 138198b9484cSchristos simple_object_mach_o_write_to_file, 13824559860eSchristos simple_object_mach_o_release_write, 13834559860eSchristos NULL 138498b9484cSchristos }; 1385