summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/sgs/ar/common/file.c158
-rw-r--r--usr/src/cmd/sgs/libelf/common/getdata.c34
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README8
3 files changed, 114 insertions, 86 deletions
diff --git a/usr/src/cmd/sgs/ar/common/file.c b/usr/src/cmd/sgs/ar/common/file.c
index b0129c4f21..a84d064145 100644
--- a/usr/src/cmd/sgs/ar/common/file.c
+++ b/usr/src/cmd/sgs/ar/common/file.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -39,10 +38,37 @@
static char *str_base; /* start of string table for names */
static char *str_top; /* pointer to next available location */
static char *str_base1, *str_top1;
-static int pad_symtab;
+static int pad_symtab; /* # of bytes by which to pad symbol table */
/*
+ * The ar file format requires objects to be padded to an even size.
+ * We do that, but it turns out to be beneficial to go farther.
+ *
+ * ld(1) accesses archives by mmapping them into memory. If the mapped
+ * objects have the proper alignment, we can access them directly. If the
+ * alignment is wrong, elflib "slides" them so that they are also accessible.
+ * This is expensive in time (to copy memory) and space (it causes swap
+ * to be allocated by the system to back the now-modified pages). Hence, we
+ * really want to ensure that the alignment is right.
+ *
+ * We used to align 32-bit objects at 4-byte boundaries, and 64-bit objects
+ * at 8-byte. More recently, an elf section type has appeared that has
+ * 8-byte alignment requirements (SUNW_move) even in 32-bit objects. So,
+ * the current strategy is to align all objects to 8-bytes.
+ *
+ * There are two important things to consider when setting this value:
+ * 1) If a new elf section that ld(1) accesses in memory appears
+ * with a greater than 8-byte alignment requirement, this value
+ * will need to be raised. Or, alternatively, the entire approach may
+ * need reconsideration.
+ * 2) The size of this padding must be smaller than the size of the
+ * smallest possible ELF section. Otherwise, the logic contained
+ * in recover_padding() can be tricked.
+ */
+#define PADSZ 8
+
+/*
* Function Prototypes
*/
static long mklong_tab(int *);
@@ -109,11 +135,27 @@ getaf(Cmd_info *cmd_info)
}
/*
- * If the current archive item is a 32 or 64-bit object, then
- * ar(1) may have added newline padding at the end in order to
- * bring 64-bit objects into 8-byte alignment within the file. This
- * padding cannot be distinguished from data using the information kept
- * in the ar headers. This routine examines the objects, using knowledge of
+ * Given a size, return the number of bytes required to round it
+ * up to the next PADSZ boundary.
+ */
+static int
+pad(int n)
+{
+ int r;
+
+ r = n % PADSZ;
+ if (r)
+ r = PADSZ - r;
+
+ return (r);
+}
+
+/*
+ * If the current archive item is an object, then ar(1) may have added
+ * newline padding at the end in order to bring the following object
+ * into PADSZ alignment within the file. This padding cannot be
+ * distinguished from data using the information kept in the ar headers.
+ * This routine examines the objects, using knowledge of
* ELF and how our tools lay out objects to determine whether padding was
* added to an archive item. If so, it adjusts the st_size and
* st_padding fields of the file argument to reflect it.
@@ -136,20 +178,20 @@ recover_padding(Elf *elf, ARFILE *file)
* use elflib or follow this convention. So, it is extremely
* likely that the section header array is at the end of this
* object: Find the address at the end of the array and compare
- * it to the archive ar_size. If they are within 8 bytes, then
- * we've found the end, and the difference is padding (no ELF
- * section can fit into 8 bytes).
+ * it to the archive ar_size. If they are within PADSZ bytes, then
+ * we've found the end, and the difference is padding (We assume
+ * that no ELF section can fit into PADSZ bytes).
*/
extent = gelf_getehdr(elf, &ehdr)
? (ehdr.e_shoff + (ehdr.e_shnum * ehdr.e_shentsize)) : 0;
padding = file->ar_size - extent;
- if ((padding < 0) || (padding >= 8)) {
+ if ((padding < 0) || (padding >= PADSZ)) {
/*
* The section header array is not at the end of the object.
* Traverse the section headers and look for the one with
* the highest used address. If this address is within
- * 8-bytes of ar_size, then this is the end of the object.
+ * PADSZ bytes of ar_size, then this is the end of the object.
*/
Elf_Scn *scn = 0;
@@ -169,18 +211,18 @@ recover_padding(Elf *elf, ARFILE *file)
/*
* Now, test the padding. We only act on padding in the range
- * 1-7 (ar(1) will never add more than this). A pad of 0
- * requires no action, and any other size outside of 1-7 means
+ * (0 < pad < PADSZ) (ar(1) will never add more than this). A pad
+ * of 0 requires no action, and any other size above (PADSZ-1) means
* that we don't understand the layout of this object, and as such,
* cannot do anything.
*
- * If the padding is in the range 1-7, and the raw data for the
+ * If the padding is in range, and the raw data for the
* object is available, then we perform one additional sanity
* check before moving forward: ar(1) always pads with newline
* characters. If anything else is seen, it is not padding so
* leave it alone.
*/
- if ((padding > 0) && (padding < 8)) {
+ if ((padding > 0) && (padding < PADSZ)) {
if (file->ar_contents) {
long cnt = padding;
char *p = file->ar_contents + extent;
@@ -651,14 +693,14 @@ writesymtab(char *dst, long nsyms, ARFILEP *symlist)
}
/*
- * The first member file is ELFCLASS64. We need to make the member
- * to be placed at the 8 byte boundary.
+ * The first member file is an ELF object. We need to make
+ * sure it will be placed at the PADSZ byte boundary.
*/
if (pad_symtab) {
int i;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < pad_symtab; i++)
*dst++ = 0;
- sum += 4;
+ sum += pad_symtab;
}
free(buf2);
@@ -1267,21 +1309,17 @@ sizeofmembers(int psum)
sum += hdrsize;
if ((fptr->ar_flag & (F_CLASS32 | F_CLASS64)) &&
- fptr->ar_next && (fptr->ar_next->ar_flag & F_CLASS64)) {
- int remainder;
-
- remainder = (psum + sum + hdrsize) % 8;
- if (remainder) {
- sum += (8 - remainder);
- fptr->ar_padding = 8 - remainder;
- }
+ fptr->ar_next &&
+ (fptr->ar_next->ar_flag & (F_CLASS32 | F_CLASS64))) {
+ fptr->ar_padding = pad(psum + sum + hdrsize);
+ sum += fptr->ar_padding;
}
}
return (sum);
}
static int
-sizeofnewarchive(int nsyms, int longnames)
+sizeofnewarchiveheader(int nsyms, int longnames)
{
int sum = 0;
@@ -1304,16 +1342,24 @@ sizeofnewarchive(int nsyms, int longnames)
}
/*
- * If the first member file is ELFCLASS64 type,
+ * If the first member file is an ELF object,
* we have to ensure the member contents will align
- * on 8 byte boundary.
+ * on PADSZ byte boundary.
*/
- if (listhead && (listhead->ar_flag & F_CLASS64)) {
- if (((sum + (sizeof (struct ar_hdr))) % 8) != 0) {
- sum += 4;
- pad_symtab = 4;
- }
+ if (listhead && (listhead->ar_flag & (F_CLASS32 | F_CLASS64))) {
+ pad_symtab = pad(sum + sizeof (struct ar_hdr));
+ sum += pad_symtab;
}
+
+ return (sum);
+}
+
+static int
+sizeofnewarchive(int nsyms, int longnames)
+{
+ int sum;
+
+ sum = sizeofnewarchiveheader(nsyms, longnames);
sum += sizeofmembers(sum);
return (sum);
}
@@ -1415,42 +1461,6 @@ ar_rename(char *from, char *to)
return (ret);
}
-static int
-sizeofnewarchiveheader(int nsyms, int longnames)
-{
- int sum = 0;
-
- sum += SARMAG;
-
- if (nsyms) {
- char *top = (char *)str_top;
- char *base = (char *)str_base;
-
- while ((top - base) & 03)
- top++;
- sum += sizeof (struct ar_hdr);
- sum += (nsyms + 1) * 4;
- sum += top - base;
- }
-
- if (longnames) {
- sum += sizeof (struct ar_hdr);
- sum += str_top1 - str_base1;
- }
-
- /*
- * If the first member file is ELFCLASS64 type,
- * we have to ensure the member contents will align
- * on 8 byte boundary.
- */
- if (listhead && (listhead->ar_flag & F_CLASS64)) {
- if (((sum + (sizeof (struct ar_hdr))) % 8) != 0) {
- sum += 4;
- }
- }
- return (sum);
-}
-
static char *
writelargefile(Cmd_info *cmd_info, long long_tab_size, int longnames,
ARFILEP *symlist, long nsyms, int found_obj, int new_archive)
diff --git a/usr/src/cmd/sgs/libelf/common/getdata.c b/usr/src/cmd/sgs/libelf/common/getdata.c
index 90dab79c9f..67e4dd549c 100644
--- a/usr/src/cmd/sgs/libelf/common/getdata.c
+++ b/usr/src/cmd/sgs/libelf/common/getdata.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -24,7 +23,7 @@
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -246,14 +245,33 @@ _elf_locked_getdata(Elf_Scn * scn, Elf_Data * data)
/*
* If the destination size (memory) is at least as
- * big as the source size (file), reuse the space.
+ * big as the source size (file), and has the necessary
+ * alignment, reuse the space.
+ *
+ * Note that it is not sufficient to check the alignment
+ * of the offset within the object. Rather, we must check
+ * the alignment of the actual data buffer. The offset is
+ * sufficient if the file is a plain object file, which
+ * will always be mapped on a page boundary. In an archive
+ * however, the only guarantee is that the object will start
+ * on an even boundary within the archive file. The
+ * Solaris ar(1) adds padding in most (but not all cases)
+ * which minimizes this issue, but it is still important
+ * for the remaining cases that do not get padded. It also
+ * matters with archives produced by other versions of
+ * ar(1), such as the GNU version, or one from another
+ * ELF based operating system.
*/
- if ((d->db_data.d_size <= src.d_size) &&
- (d->db_off % ALIGN(elf)[d->db_data.d_type] == 0)) {
+ if (d->db_data.d_size <= src.d_size) {
d->db_data.d_buf = (Elf_Void *)(elf->ed_ident +
d->db_off);
- break;
+ if (((uintptr_t)d->db_data.d_buf
+ % ALIGN(elf)[d->db_data.d_type]) == 0) {
+ break;
+ } else { /* Failure: Restore NULL buffer pointer */
+ d->db_data.d_buf = 0;
+ }
}
/*FALLTHRU*/
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index 01726d9336..0ee65c81d4 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -6,9 +6,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -1088,4 +1087,5 @@ Bugid Risk Synopsis
6201866 amd64: linker symbol elimination is broken
6372620 printstack() segfaults when called from static function
6380470 32-bit ld(1) incorrectly builds 64-bit relocatable objects
-6382170 Solaris 10 ar(1) adds newlines to data when creating/updating archives
+6391407 Insufficient alignment of 32-bit object in archive makes ld segfault
+ (libelf component only)