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