From patchwork Tue Oct 18 12:23:45 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Sandoe X-Patchwork-Id: 120415 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 70158B70BC for ; Tue, 18 Oct 2011 23:24:31 +1100 (EST) Received: (qmail 15394 invoked by alias); 18 Oct 2011 12:24:24 -0000 Received: (qmail 15363 invoked by uid 22791); 18 Oct 2011 12:24:18 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, TW_CP X-Spam-Check-By: sourceware.org Received: from c2beaomr07.btconnect.com (HELO mail.btconnect.com) (213.123.26.185) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 18 Oct 2011 12:23:52 +0000 Received: from host81-138-1-83.in-addr.btopenworld.com (EHLO thor.office) ([81.138.1.83]) by c2beaomr07.btconnect.com with ESMTP id EUP53186; Tue, 18 Oct 2011 13:23:48 +0100 (BST) Cc: GCC Patches , Mike Stump Message-Id: From: Iain Sandoe To: Ian Lance Taylor In-Reply-To: <5C4A58B3-24D3-440F-9B9D-A762A3E4C455@sandoe-acoustics.co.uk> Mime-Version: 1.0 (Apple Message framework v936) Subject: Re: [Patch, Darwin/libiberty] fix target/48108 by adding a section wrapper scheme to the darwin port. Date: Tue, 18 Oct 2011 13:23:45 +0100 References: <9A9A82F6-5525-4ABD-AFEB-F1535E786262@sandoe-acoustics.co.uk> <5C4A58B3-24D3-440F-9B9D-A762A3E4C455@sandoe-acoustics.co.uk> X-Mirapoint-IP-Reputation: reputation=Fair-1, source=Queried, refid=tid=0001.0A0B0301.4E9D6FD2.00DD, actions=tag X-Junkmail-Premium-Raw: score=8/50, refid=2.7.2:2011.10.18.114814:17:8.129, ip=81.138.1.83, rules=__MULTIPLE_RCPTS_CC_X2, __HAS_MSGID, __SANE_MSGID, __MSGID_APPLEMAIL, __TO_MALFORMED_2, __CT, __CTYPE_HAS_BOUNDARY, __CTYPE_MULTIPART, CTYPE_MULTIPART_NO_QUOTE, __CTYPE_MULTIPART_MIXED, __MIME_VERSION, __MIME_VERSION_APPLEMAIL, __BOUNCE_CHALLENGE_SUBJ, __BOUNCE_NDR_SUBJ_EXEMPT, __HAS_X_MAILER, __X_MAILER_APPLEMAIL, TXT_ATTACHED, __ANY_URI, __URI_NO_MAILTO, __URI_NO_WWW, __STOCK_PHRASE_25, __CP_URI_IN_BODY, __CANPHARM_COPYRIGHT, BODY_SIZE_10000_PLUS, BODYTEXTP_SIZE_3000_LESS, __MIME_TEXT_ONLY, RDNS_GENERIC_POOLED, RDNS_SUSP_GENERIC, __USER_AGENT_APPLEMAIL, RDNS_SUSP, MIME_TEXT_ONLY_MP_MIXED, MULTIPLE_RCPTS X-Junkmail-Signature-Raw: score=unknown, refid=str=0001.0A0B0204.4E9D6FD4.016F, ss=1, fgs=0, ip=0.0.0.0, so=2010-07-22 22:03:31, dmn=2009-09-10 00:05:08, mode=multiengine X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org On 30 Sep 2011, at 00:33, Iain Sandoe wrote: > I'll re-jig with the typographical changes (sorry that were so > many ... ) I've addressed your points in : http://gcc.gnu.org/ml/gcc-patches/2011-09/msg01974.html specifically (other than typographical issues_ o we retain the ability to read an old-style file. - I wonder if there should be an argument for removing this from the trunk version, but retaining in 4.6. - or, at the least, can we remove it from 4.8? o I dropped the ability to read all the sections from a file (by retaining the requirement to specify a segment name). - I will try to submit a separate patch to do this - which would essentially give the darwin version of simple-object the same functionality as the others (at the moment one can only read data from one segment at a time). o there's no need to amend the header, since the functionality is unchanged. - retested on i686/x86-64 darwin 9/10 with "bootstrap-lto bootstrap- debug" (darwin10 requires the ranlib -c fix to work when XCode >= 3.2.6 ). Once again, apologies for the number of typos in the original. OK for trunk/4.6? Iain libiberty: PR target/48108 * simple-object-mach-o.c (GNU_WRAPPER_SECTS, GNU_WRAPPER_INDEX, GNU_WRAPPER_NAMES): New macros. (simple_object_mach_o_segment): Handle wrapper scheme. (simple_object_mach_o_write_section_header): Allow the segment name to be supplied. (simple_object_mach_o_write_segment): Handle wrapper scheme. Ensure that the top-level segment name in the load command is empty. (simple_object_mach_o_write_to_file): Determine the number of sections during segment output, use that in writing the header. gcc: PR target/48108 * config/darwin.c (top level): Amend comments concerning LTO output. (lto_section_num): New variable. (darwin_lto_section_e): New GTY. (LTO_SECTS_SECTION, LTO_INDEX_SECTION): New. (LTO_NAMES_SECTION): Rename. (darwin_asm_named_section): Record LTO section counts and switches in a vec of darwin_lto_section_e. (darwin_file_start): Remove unused code. (darwin_file_end): Put an LTO section termination label. Handle output of the wrapped LTO sections, index and names table. Index: libiberty/simple-object-mach-o.c =================================================================== --- libiberty/simple-object-mach-o.c (revision 180097) +++ libiberty/simple-object-mach-o.c (working copy) @@ -1,5 +1,5 @@ /* simple-object-mach-o.c -- routines to manipulate Mach-O object files. - Copyright 2010 Free Software Foundation, Inc. + Copyright 2010, 2011 Free Software Foundation, Inc. Written by Ian Lance Taylor, Google. This program is free software; you can redistribute it and/or modify it @@ -174,6 +174,15 @@ struct mach_o_section_64 #define GNU_SECTION_NAMES "__section_names" +/* A GNU-specific extension to wrap multiple sections using three + mach-o sections within a given segment. The section '__wrapper_sects' + is subdivided according to the index '__wrapper_index' and each sub + sect is named according to the names supplied in '__wrapper_names'. */ + +#define GNU_WRAPPER_SECTS "__wrapper_sects" +#define GNU_WRAPPER_INDEX "__wrapper_index" +#define GNU_WRAPPER_NAMES "__wrapper_names" + /* Private data for an simple_object_read. */ struct simple_object_mach_o_read @@ -214,8 +223,19 @@ struct simple_object_mach_o_attributes unsigned int reserved; }; -/* See if we have a Mach-O file. */ +/* See if we have a Mach-O MH_OBJECT file: + A standard MH_OBJECT (from as) will have three load commands: + 0 - LC_SEGMENT/LC_SEGMENT64 + 1 - LC_SYMTAB + 2 - LC_DYSYMTAB + + The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment + containing all the sections. + + Files written by simple-object will have only the segment command + (no symbol tables). */ + static void * simple_object_mach_o_match ( unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], @@ -356,9 +376,30 @@ simple_object_mach_o_section_info (int is_big_endi } } -/* Handle a segment in a Mach-O file. Return 1 if we should continue, - 0 if the caller should return. */ +/* Handle a segment in a Mach-O Object file. + This will callback to the function pfn for each "section found" the meaning + of which depends on gnu extensions to mach-o: + + If we find mach-o sections (with the segment name as specified) which also + contain: a 'sects' wrapper, an index, and a name table, we expand this into + as many sections as are specified in the index. In this case, there will + be a callback for each of these. + + We will also allow an extension that permits long names (more than 16 + characters) to be used with mach-o. In this case, the section name has + a specific format embedding an index into a name table, and the file must + contain such name table. + + Return 1 if we should continue, 0 if the caller should return. */ + +#define SOMO_SECTS_PRESENT 0x01 +#define SOMO_INDEX_PRESENT 0x02 +#define SOMO_NAMES_PRESENT 0x04 +#define SOMO_LONGN_PRESENT 0x08 +#define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \ + | SOMO_NAMES_PRESENT) + static int simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, const unsigned char *segbuf, @@ -378,9 +419,20 @@ simple_object_mach_o_segment (simple_object_read * unsigned int nsects; unsigned char *secdata; unsigned int i; + unsigned int gnu_sections_found; unsigned int strtab_index; + unsigned int index_index; + unsigned int nametab_index; + unsigned int sections_index; char *strtab; + char *nametab; + unsigned char *index; size_t strtab_size; + size_t nametab_size; + size_t index_size; + unsigned int n_wrapped_sects; + size_t wrapper_sect_size; + off_t wrapper_sect_offset; fetch_32 = (omr->is_big_endian ? simple_object_fetch_big_32 @@ -409,6 +461,8 @@ simple_object_mach_o_segment (simple_object_read * nsects)); } + /* Fetch the section headers from the segment command. */ + secdata = XNEWVEC (unsigned char, nsects * sechdrsize); if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, secdata, nsects * sechdrsize, errmsg, err)) @@ -417,9 +471,13 @@ simple_object_mach_o_segment (simple_object_read * return 0; } - /* Scan for a __section_names section. This is in effect a GNU - extension that permits section names longer than 16 chars. */ + /* Scan for special sections that signal GNU extensions to the format. */ + gnu_sections_found = 0; + index_index = nsects; + sections_index = nsects; + strtab_index = nsects; + nametab_index = nsects; for (i = 0; i < nsects; ++i) { size_t nameoff; @@ -427,19 +485,104 @@ simple_object_mach_o_segment (simple_object_read * nameoff = i * sechdrsize + segname_offset; if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) continue; + nameoff = i * sechdrsize + sectname_offset; - if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) - break; + if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0) + { + nametab_index = i; + gnu_sections_found |= SOMO_NAMES_PRESENT; + } + else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0) + { + index_index = i; + gnu_sections_found |= SOMO_INDEX_PRESENT; + } + else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0) + { + sections_index = i; + gnu_sections_found |= SOMO_SECTS_PRESENT; + } + else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) + { + strtab_index = i; + gnu_sections_found |= SOMO_LONGN_PRESENT; + } } - strtab_index = i; - if (strtab_index >= nsects) + /* If any of the special wrapper section components is present, then + they all should be. */ + + if ((gnu_sections_found & SOMO_WRAPPING) != 0) { - strtab = NULL; - strtab_size = 0; + off_t nametab_offset; + off_t index_offset; + + if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING) + { + *errmsg = "GNU Mach-o section wrapper: required section missing"; + *err = 0; /* No useful errno. */ + XDELETEVEC (secdata); + return 0; + } + + /* Fetch the name table. */ + + simple_object_mach_o_section_info (omr->is_big_endian, is_32, + secdata + nametab_index * sechdrsize, + &nametab_offset, &nametab_size); + nametab = XNEWVEC (char, nametab_size); + if (!simple_object_internal_read (sobj->descriptor, + sobj->offset + nametab_offset, + (unsigned char *) nametab, nametab_size, + errmsg, err)) + { + XDELETEVEC (nametab); + XDELETEVEC (secdata); + return 0; + } + + /* Fetch the index. */ + + simple_object_mach_o_section_info (omr->is_big_endian, is_32, + secdata + index_index * sechdrsize, + &index_offset, &index_size); + index = XNEWVEC (unsigned char, index_size); + if (!simple_object_internal_read (sobj->descriptor, + sobj->offset + index_offset, + index, index_size, + errmsg, err)) + { + XDELETEVEC (index); + XDELETEVEC (nametab); + XDELETEVEC (secdata); + return 0; + } + + /* The index contains 4 unsigned ints per sub-section: + sub-section offset/length, sub-section name/length. + We fix this for both 32 and 64 bit mach-o for now, since + other fields limit the maximum size of an object to 4G. */ + n_wrapped_sects = index_size / 16; + + /* Get the parameters for the wrapper too. */ + simple_object_mach_o_section_info (omr->is_big_endian, is_32, + secdata + sections_index * sechdrsize, + &wrapper_sect_offset, + &wrapper_sect_size); } else { + index = NULL; + index_size = 0; + nametab = NULL; + nametab_size = 0; + n_wrapped_sects = 0; + } + + /* If we have a long names section, fetch it. */ + + if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) + { off_t strtab_offset; simple_object_mach_o_section_info (omr->is_big_endian, is_32, @@ -452,52 +595,120 @@ simple_object_mach_o_segment (simple_object_read * errmsg, err)) { XDELETEVEC (strtab); + XDELETEVEC (index); + XDELETEVEC (nametab); XDELETEVEC (secdata); return 0; } } + else + { + strtab = NULL; + strtab_size = 0; + strtab_index = nsects; + } /* Process the sections. */ for (i = 0; i < nsects; ++i) { const unsigned char *sechdr; - char namebuf[MACH_O_NAME_LEN + 1]; + char namebuf[MACH_O_NAME_LEN * 2 + 2]; char *name; off_t secoffset; size_t secsize; + int l; - if (i == strtab_index) + sechdr = secdata + i * sechdrsize; + + /* We've already processed the long section names. */ + + if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0 + && i == strtab_index) continue; - sechdr = secdata + i * sechdrsize; + /* We only act on the segment named. */ if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) continue; - memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); - namebuf[MACH_O_NAME_LEN] = '\0'; + /* Process sections associated with the wrapper. */ - name = &namebuf[0]; - if (strtab != NULL && name[0] == '_' && name[1] == '_') + if ((gnu_sections_found & SOMO_WRAPPING) != 0) { - unsigned long stringoffset; + if (i == nametab_index || i == index_index) + continue; - if (sscanf (name + 2, "%08lX", &stringoffset) == 1) + if (i == sections_index) { - if (stringoffset >= strtab_size) + unsigned int j; + for (j = 0; j < n_wrapped_sects; ++j) { - *errmsg = "section name offset out of range"; - *err = 0; - XDELETEVEC (strtab); - XDELETEVEC (secdata); - return 0; + unsigned int subsect_offset, subsect_length, name_offset; + subsect_offset = (*fetch_32) (index + 16 * j); + subsect_length = (*fetch_32) (index + 16 * j + 4); + name_offset = (*fetch_32) (index + 16 * j + 8); + /* We don't need the name_length yet. */ + + secoffset = wrapper_sect_offset + subsect_offset; + secsize = subsect_length; + name = nametab + name_offset; + + if (!(*pfn) (data, name, secoffset, secsize)) + { + *errmsg = NULL; + *err = 0; + XDELETEVEC (index); + XDELETEVEC (nametab); + XDELETEVEC (strtab); + XDELETEVEC (secdata); + return 0; + } } - - name = strtab + stringoffset; + continue; } } + if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) + { + memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); + namebuf[MACH_O_NAME_LEN] = '\0'; + + name = &namebuf[0]; + if (strtab != NULL && name[0] == '_' && name[1] == '_') + { + unsigned long stringoffset; + + if (sscanf (name + 2, "%08lX", &stringoffset) == 1) + { + if (stringoffset >= strtab_size) + { + *errmsg = "section name offset out of range"; + *err = 0; + XDELETEVEC (index); + XDELETEVEC (nametab); + XDELETEVEC (strtab); + XDELETEVEC (secdata); + return 0; + } + + name = strtab + stringoffset; + } + } + } + else + { + /* Otherwise, make a name like __segment,__section as per the + convention in mach-o asm. */ + name = &namebuf[0]; + memset (namebuf, 0, MACH_O_NAME_LEN * 2 + 2); + memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN); + l = strlen (namebuf); + namebuf[l] = ','; + memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset, + MACH_O_NAME_LEN); + } + simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, &secoffset, &secsize); @@ -505,12 +716,16 @@ simple_object_mach_o_segment (simple_object_read * { *errmsg = NULL; *err = 0; + XDELETEVEC (index); + XDELETEVEC (nametab); XDELETEVEC (strtab); XDELETEVEC (secdata); return 0; } } + XDELETEVEC (index); + XDELETEVEC (nametab); XDELETEVEC (strtab); XDELETEVEC (secdata); @@ -724,9 +939,9 @@ static int simple_object_mach_o_write_section_header (simple_object_write *sobj, int descriptor, size_t sechdr_offset, - const char *name, size_t secaddr, - size_t secsize, size_t offset, - unsigned int align, + const char *name, const char *segn, + size_t secaddr, size_t secsize, + size_t offset, unsigned int align, const char **errmsg, int *err) { struct simple_object_mach_o_attributes *attrs = @@ -748,7 +963,7 @@ simple_object_mach_o_write_section_header (simple_ strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), name, MACH_O_NAME_LEN); strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), - sobj->segment_name, MACH_O_NAME_LEN); + segn, MACH_O_NAME_LEN); set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); @@ -773,7 +988,7 @@ simple_object_mach_o_write_section_header (simple_ strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), name, MACH_O_NAME_LEN); strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), - sobj->segment_name, MACH_O_NAME_LEN); + segn, MACH_O_NAME_LEN); set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); @@ -793,11 +1008,25 @@ simple_object_mach_o_write_section_header (simple_ sechdrsize, errmsg, err); } -/* Write out the single segment and the sections of a Mach-O file. */ +/* Write out the single (anonymous) segment containing the sections of a Mach-O + Object file. + As a GNU extension to mach-o, when the caller specifies a segment name in + sobj->segment_name, all the sections passed will be output under a single + mach-o section header. The caller's sections are indexed within this + 'wrapper' section by a table stored in a second mach-o section. Finally, + arbitrary length section names are permitted by the extension and these are + stored in a table in a third mach-o section. + + Note that this is only likely to make any sense for the __GNU_LTO segment + at present. + + If the wrapper extension is not in force, we assume that the section name + is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */ + static int simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, - size_t nsects, const char **errmsg, + size_t *nsects, const char **errmsg, int *err) { struct simple_object_mach_o_attributes *attrs = @@ -814,6 +1043,10 @@ simple_object_mach_o_write_segment (simple_object_ simple_object_write_section *section; unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; unsigned char *hdr; + size_t nsects_in; + unsigned int *index; + char *snames; + unsigned int sect; set_32 = (attrs->is_big_endian ? simple_object_set_big_32 @@ -834,19 +1067,62 @@ simple_object_mach_o_write_segment (simple_object_ sechdrsize = sizeof (struct mach_o_section_64); } + name_offset = 0; + *nsects = nsects_in = 0; + + /* Count the number of sections we start with. */ + + for (section = sobj->sections; section != NULL; section = section->next) + nsects_in++; + + if (sobj->segment_name != NULL) + { + /* We will only write 3 sections: wrapped data, index and names. */ + + *nsects = 3; + + /* The index has four entries per wrapped section: + Section Offset, length, Name offset, length. + Where the offsets are based at the start of the wrapper and name + sections respectively. + The values are stored as 32 bit int for both 32 and 64 bit mach-o + since the size of a mach-o MH_OBJECT cannot exceed 4G owing to + other constraints. */ + + index = XNEWVEC (unsigned int, nsects_in * 4); + + /* We now need to figure out the size of the names section. This just + stores the names as null-terminated c strings, packed without any + alignment padding. */ + + for (section = sobj->sections, sect = 0; section != NULL; + section = section->next, sect++) + { + index[sect*4+2] = name_offset; + index[sect*4+3] = strlen (section->name) + 1; + name_offset += strlen (section->name) + 1; + } + snames = XNEWVEC (char, name_offset); + } + else + { + *nsects = nsects_in; + index = NULL; + snames = NULL; + } + sechdr_offset = hdrsize + seghdrsize; - cmdsize = seghdrsize + nsects * sechdrsize; + cmdsize = seghdrsize + *nsects * sechdrsize; offset = hdrsize + cmdsize; - name_offset = 0; secaddr = 0; - for (section = sobj->sections; section != NULL; section = section->next) + for (section = sobj->sections, sect = 0; + section != NULL; section = section->next, sect++) { size_t mask; size_t new_offset; size_t secsize; struct simple_object_write_section_buffer *buffer; - char namebuf[MACH_O_NAME_LEN + 1]; mask = (1U << section->align) - 1; new_offset = offset + mask; @@ -877,39 +1153,126 @@ simple_object_mach_o_write_segment (simple_object_ secsize += buffer->size; } - snprintf (namebuf, sizeof namebuf, "__%08X", name_offset); + if (sobj->segment_name != NULL) + { + index[sect*4+0] = (unsigned int) offset; + index[sect*4+1] = secsize; + /* Stash the section name in our table. */ + memcpy (snames + index[sect * 4 + 2], section->name, + index[sect * 4 + 3]); + } + else + { + char namebuf[MACH_O_NAME_LEN + 1]; + char segnbuf[MACH_O_NAME_LEN + 1]; + char *comma; + + /* Try to extract segment,section from the input name. */ + + memset (namebuf, 0, sizeof namebuf); + memset (segnbuf, 0, sizeof segnbuf); + comma = strchr (section->name, ','); + if (comma != NULL) + { + int len = comma - section->name; + len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len; + strncpy (namebuf, section->name, len); + strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN); + } + else /* just try to copy the name, leave segment blank. */ + strncpy (namebuf, section->name, MACH_O_NAME_LEN); + + if (!simple_object_mach_o_write_section_header (sobj, descriptor, + sechdr_offset, + namebuf, segnbuf, + secaddr, secsize, + offset, + section->align, + errmsg, err)) + return 0; + sechdr_offset += sechdrsize; + } + + offset += secsize; + secaddr += secsize; + } + + if (sobj->segment_name != NULL) + { + size_t secsize; + unsigned int i; + + /* Write the section header for the wrapper. */ + /* Account for any initial aligment - which becomes the alignment for this + created section. */ + + secsize = (offset - index[0]); if (!simple_object_mach_o_write_section_header (sobj, descriptor, - sechdr_offset, namebuf, - secaddr, secsize, offset, - section->align, + sechdr_offset, + GNU_WRAPPER_SECTS, + sobj->segment_name, + 0 /*secaddr*/, + secsize, index[0], + sobj->sections->align, errmsg, err)) return 0; + /* Subtract the wrapper section start from the begining of each sub + section. */ + + for (i = 1; i < nsects_in; ++i) + index[4 * i] -= index[0]; + index[0] = 0; + sechdr_offset += sechdrsize; - offset += secsize; - name_offset += strlen (section->name) + 1; - secaddr += secsize; - } - /* Write out the section names. */ + /* Write out the section names. + ... the header ... + name_offset contains the length of the section. It is not aligned. */ - if (!simple_object_mach_o_write_section_header (sobj, descriptor, - sechdr_offset, - GNU_SECTION_NAMES, secaddr, - name_offset, offset, 0, - errmsg, err)) - return 0; + if (!simple_object_mach_o_write_section_header (sobj, descriptor, + sechdr_offset, + GNU_WRAPPER_NAMES, + sobj->segment_name, + 0 /*secaddr*/, + name_offset, + offset, + 0, errmsg, err)) + return 0; - for (section = sobj->sections; section != NULL; section = section->next) - { - size_t namelen; + /* ... and the content.. */ + if (!simple_object_internal_write (descriptor, offset, + (const unsigned char *) snames, + name_offset, errmsg, err)) + return 0; - namelen = strlen (section->name) + 1; + sechdr_offset += sechdrsize; + secaddr += name_offset; + offset += name_offset; + + /* Now do the index, we'll align this to 4 bytes although the read code + will handle unaligned. */ + + offset += 3; + offset &= ~0x03; + if (!simple_object_mach_o_write_section_header (sobj, descriptor, + sechdr_offset, + GNU_WRAPPER_INDEX, + sobj->segment_name, + 0 /*secaddr*/, + nsects_in * 16, + offset, + 2, errmsg, err)) + return 0; + + /* ... and the content.. */ if (!simple_object_internal_write (descriptor, offset, - (const unsigned char *) section->name, - namelen, errmsg, err)) + (const unsigned char *) index, + nsects_in*16, errmsg, err)) return 0; - offset += namelen; + + XDELETEVEC (index); + XDELETEVEC (snames); } /* Write out the segment header. */ @@ -923,9 +1286,8 @@ simple_object_mach_o_write_segment (simple_object_ MACH_O_LC_SEGMENT); set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), cmdsize); - strncpy (((char *) hdr - + offsetof (struct mach_o_segment_command_32, segname)), - sobj->segment_name, MACH_O_NAME_LEN); + /* MH_OBJECTS have a single, anonymous, segment - so the segment name + is left empty. */ /* vmaddr left as zero. */ /* vmsize left as zero. */ set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), @@ -935,7 +1297,7 @@ simple_object_mach_o_write_segment (simple_object_ /* maxprot left as zero. */ /* initprot left as zero. */ set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), - nsects); + *nsects); /* flags left as zero. */ } else @@ -951,9 +1313,8 @@ simple_object_mach_o_write_segment (simple_object_ MACH_O_LC_SEGMENT); set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), cmdsize); - strncpy (((char *) hdr - + offsetof (struct mach_o_segment_command_64, segname)), - sobj->segment_name, MACH_O_NAME_LEN); + /* MH_OBJECTS have a single, anonymous, segment - so the segment name + is left empty. */ /* vmaddr left as zero. */ /* vmsize left as zero. */ set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), @@ -963,7 +1324,7 @@ simple_object_mach_o_write_segment (simple_object_ /* maxprot left as zero. */ /* initprot left as zero. */ set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), - nsects); + *nsects); /* flags left as zero. */ #endif } @@ -978,23 +1339,17 @@ static const char * simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, int *err) { - size_t nsects; - simple_object_write_section *section; + size_t nsects = 0; const char *errmsg; - /* Start at 1 for symbol_names section. */ - nsects = 1; - for (section = sobj->sections; section != NULL; section = section->next) - ++nsects; + if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects, + &errmsg, err)) + return errmsg; if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, &errmsg, err)) return errmsg; - if (!simple_object_mach_o_write_segment (sobj, descriptor, nsects, - &errmsg, err)) - return errmsg; - return NULL; } Index: gcc/config/darwin.c =================================================================== --- gcc/config/darwin.c (revision 180097) +++ gcc/config/darwin.c (working copy) @@ -1753,19 +1753,51 @@ darwin_label_is_anonymous_local_objc_name (const c return (!strncmp ((const char *)p, "_OBJC_", 6)); } -/* LTO support for Mach-O. */ +/* LTO support for Mach-O. -/* Section names for LTO sections. */ -static unsigned int lto_section_names_offset = 0; + This version uses three mach-o sections to encapsulate the (unlimited + number of) lto sections. -/* This is the obstack which we use to allocate the many strings. */ -static struct obstack lto_section_names_obstack; + __GNU_LTO, __lto_sections contains the concatented GNU LTO section data. + __GNU_LTO, __section_names contains the GNU LTO section names. + __GNU_LTO, __section_index contains an array of values that index these. -/* Segment name for LTO sections. */ + Indexed thus: +
, +
+ . + + At present, for both m32 and m64 mach-o files each of these fields is + represented by a uint32_t. This is because, AFAICT, a mach-o object + cannot exceed 4Gb because the section_64 offset field (see below) is 32bits. + + uint32_t offset; + "offset An integer specifying the offset to this section in the file." */ + +/* Count lto section numbers. */ +static unsigned int lto_section_num = 0; + +/* A vector of information about LTO sections, at present, we only have + the name. TODO: see if we can get the data length somehow. */ +typedef struct GTY (()) darwin_lto_section_e { + const char *sectname; +} darwin_lto_section_e ; +DEF_VEC_O(darwin_lto_section_e); +DEF_VEC_ALLOC_O(darwin_lto_section_e, gc); + +static GTY (()) VEC (darwin_lto_section_e, gc) * lto_section_names; + +/* Segment for LTO data. */ #define LTO_SEGMENT_NAME "__GNU_LTO" -/* Section name for LTO section names section. */ -#define LTO_NAMES_SECTION "__section_names" +/* Section wrapper scheme (used here to wrap the unlimited number of LTO + sections into three Mach-O ones). + NOTE: These names MUST be kept in sync with those in + libiberty/simple-object-mach-o. */ +#define LTO_SECTS_SECTION "__wrapper_sects" +#define LTO_NAMES_SECTION "__wrapper_names" +#define LTO_INDEX_SECTION "__wrapper_index" /* File to temporarily store LTO data. This is appended to asm_out_file in darwin_end_file. */ @@ -1808,37 +1840,38 @@ darwin_asm_named_section (const char *name, unsigned int flags, tree decl ATTRIBUTE_UNUSED) { - /* LTO sections go in a special segment __GNU_LTO. We want to replace the - section name with something we can use to represent arbitrary-length - names (section names in Mach-O are at most 16 characters long). */ + /* LTO sections go in a special section that encapsulates the (unlimited) + number of GNU LTO sections within a single mach-o one. */ if (strncmp (name, LTO_SECTION_NAME_PREFIX, strlen (LTO_SECTION_NAME_PREFIX)) == 0) { + darwin_lto_section_e e; /* We expect certain flags to be set... */ gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED)) == (SECTION_DEBUG | SECTION_NAMED)); - /* Add the section name to the things to output when we end the - current assembler output file. - This is all not very efficient, but that doesn't matter -- this - shouldn't be a hot path in the compiler... */ - obstack_1grow (<o_section_names_obstack, '\t'); - obstack_grow (<o_section_names_obstack, ".ascii ", 7); - obstack_1grow (<o_section_names_obstack, '"'); - obstack_grow (<o_section_names_obstack, name, strlen (name)); - obstack_grow (<o_section_names_obstack, "\\0\"\n", 4); - - /* Output the dummy section name. */ - fprintf (asm_out_file, "\t# %s\n", name); - fprintf (asm_out_file, "\t.section %s,__%08X,regular,debug\n", - LTO_SEGMENT_NAME, lto_section_names_offset); - - /* Update the offset for the next section name. Make sure we stay - within reasonable length. */ - lto_section_names_offset += strlen (name) + 1; - gcc_assert (lto_section_names_offset > 0 - && lto_section_names_offset < ((unsigned) 1 << 31)); - } + /* Switch to our combined section. */ + fprintf (asm_out_file, "\t.section %s,%s,regular,debug\n", + LTO_SEGMENT_NAME, LTO_SECTS_SECTION); + /* Output a label for the start of this sub-section. */ + fprintf (asm_out_file, "L_GNU_LTO%d:\t;# %s\n", + lto_section_num, name); + /* We have to jump through hoops to get the values of the intra-section + offsets... */ + fprintf (asm_out_file, "\t.set L$gnu$lto$offs%d,L_GNU_LTO%d-L_GNU_LTO0\n", + lto_section_num, lto_section_num); + fprintf (asm_out_file, + "\t.set L$gnu$lto$size%d,L_GNU_LTO%d-L_GNU_LTO%d\n", + lto_section_num, lto_section_num+1, lto_section_num); + lto_section_num++; + e.sectname = xstrdup (name); + /* Keep the names, we'll need to make a table later. + TODO: check that we do not revisit sections, that would break + the assumption of how this is done. */ + if (lto_section_names == NULL) + lto_section_names = VEC_alloc (darwin_lto_section_e, gc, 16); + VEC_safe_push (darwin_lto_section_e, gc, lto_section_names, &e); + } else if (strncmp (name, "__DWARF,", 8) == 0) darwin_asm_dwarf_section (name, flags, decl); else @@ -2711,16 +2744,12 @@ darwin_asm_output_dwarf_offset (FILE *file, int si darwin_asm_output_dwarf_delta (file, size, lab, sname); } -/* Called from the within the TARGET_ASM_FILE_START for each target. - Initialize the stuff we need for LTO long section names support. */ +/* Called from the within the TARGET_ASM_FILE_START for each target. */ void darwin_file_start (void) { - /* We fill this obstack with the complete section text for the lto section - names to write in darwin_file_end. */ - obstack_init (<o_section_names_obstack); - lto_section_names_offset = 0; + /* Nothing to do. */ } /* Called for the TARGET_ASM_FILE_END hook. @@ -2731,8 +2760,6 @@ darwin_file_start (void) void darwin_file_end (void) { - const char *lto_section_names; - machopic_finish (asm_out_file); if (strcmp (lang_hooks.name, "GNU C++") == 0) { @@ -2762,6 +2789,13 @@ darwin_file_end (void) lto_asm_txt = buf = (char *) xmalloc (n + 1); while (fgets (lto_asm_txt, n, lto_asm_out_file)) fputs (lto_asm_txt, asm_out_file); + /* Put a termination label. */ + fprintf (asm_out_file, "\t.section %s,%s,regular,debug\n", + LTO_SEGMENT_NAME, LTO_SECTS_SECTION); + fprintf (asm_out_file, "L_GNU_LTO%d:\t;# end of lto\n", + lto_section_num); + /* Make sure our termination label stays in this section. */ + fputs ("\t.space\t1\n", asm_out_file); } /* Remove the temporary file. */ @@ -2770,21 +2804,50 @@ darwin_file_end (void) free (lto_asm_out_name); } - /* Finish the LTO section names obstack. Don't output anything if - there are no recorded section names. */ - obstack_1grow (<o_section_names_obstack, '\0'); - lto_section_names = XOBFINISH (<o_section_names_obstack, const char *); - if (strlen (lto_section_names) > 0) + /* Output the names and indices. */ + if (lto_section_names && VEC_length (darwin_lto_section_e, lto_section_names)) { - fprintf (asm_out_file, - "\t.section %s,%s,regular,debug\n", + int count; + darwin_lto_section_e *ref; + /* For now, we'll make the offsets 4 bytes and unaligned - we'll fix + the latter up ourselves. */ + const char *op = integer_asm_op (4,0); + + /* Emit the names. */ + fprintf (asm_out_file, "\t.section %s,%s,regular,debug\n", LTO_SEGMENT_NAME, LTO_NAMES_SECTION); - fprintf (asm_out_file, - "\t# Section names in %s are offsets into this table\n", - LTO_SEGMENT_NAME); - fprintf (asm_out_file, "%s\n", lto_section_names); + FOR_EACH_VEC_ELT (darwin_lto_section_e, lto_section_names, count, ref) + { + fprintf (asm_out_file, "L_GNU_LTO_NAME%d:\n", count); + /* We have to jump through hoops to get the values of the intra-section + offsets... */ + fprintf (asm_out_file, + "\t.set L$gnu$lto$noff%d,L_GNU_LTO_NAME%d-L_GNU_LTO_NAME0\n", + count, count); + fprintf (asm_out_file, + "\t.set L$gnu$lto$nsiz%d,L_GNU_LTO_NAME%d-L_GNU_LTO_NAME%d\n", + count, count+1, count); + fprintf (asm_out_file, "\t.asciz\t\"%s\"\n", ref->sectname); + } + fprintf (asm_out_file, "L_GNU_LTO_NAME%d:\t;# end\n", lto_section_num); + /* make sure our termination label stays in this section. */ + fputs ("\t.space\t1\n", asm_out_file); + + /* Emit the Index. */ + fprintf (asm_out_file, "\t.section %s,%s,regular,debug\n", + LTO_SEGMENT_NAME, LTO_INDEX_SECTION); + fputs ("\t.align\t2\n", asm_out_file); + fputs ("# Section offset, Section length, Name offset, Name length\n", + asm_out_file); + FOR_EACH_VEC_ELT (darwin_lto_section_e, lto_section_names, count, ref) + { + fprintf (asm_out_file, "%s L$gnu$lto$offs%d\t;# %s\n", + op, count, ref->sectname); + fprintf (asm_out_file, "%s L$gnu$lto$size%d\n", op, count); + fprintf (asm_out_file, "%s L$gnu$lto$noff%d\n", op, count); + fprintf (asm_out_file, "%s L$gnu$lto$nsiz%d\n", op, count); + } } - obstack_free (<o_section_names_obstack, NULL); /* If we have section anchors, then we must prevent the linker from re-arranging data. */