Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Apr 2019 18:34:11 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r346902 - stable/12/usr.bin/ar
Message-ID:  <201904291834.x3TIYBav045405@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Mon Apr 29 18:34:11 2019
New Revision: 346902
URL: https://svnweb.freebsd.org/changeset/base/346902

Log:
  MFC ar: implement support for /SYM64/ 64-bit archives
  
  r346079: ar: implement support for /SYM64/ 64-bit archives
  
  Submitted by:	Gerald Aryeetey <aryeeteygerald_rogers.com>
  Reviewed by:	imp (earlier)
  
  r346568: ar: test for writing 64-bit format only if symbol count is nonzero
  
  This is a minor simplification; if we do not have any symbols the empty
  symbol table can be in 32-bit format.
  
  r346569: ar: use array notation to access s_so
  
  This is somewhat more readable than pointer arithmetic.  Also remove an
  unnecessary cast while here.
  
  r346582: ar: shuffle symbol offsets during conversion for 32-bit ar archives
  
  During processing we maintain symbol offsets in the 64-bit s_so array,
  and when writing the archive convert to 32-bit if no offsets are greater
  than 4GB.  However, this was somewhat inefficient as we looped over the
  array twice: first, converting to big endian and second, writing each
  32-bit value one at a time (and incorrectly so on big-endian platforms).
  
  Instead, when writing a 32-bit archive shuffle convert symbol data to
  big endian (as required by the ar format) and shuffle to the beginning
  of the allocation at the same time.
  
  Also correct emission of the symbol count on big endian platforms.
  
  Further changes are planned, but this should fix powerpc64.
  
  Reported by:	jhibbits, mlinimon
  Reviewed by:	jhibbits, Gerald Aryeetey (earlier)
  Tested by:	jhibbits
  
  PR:		234454
  Sponsored by:	The FreeBSD Foundation

Modified:
  stable/12/usr.bin/ar/ar.h
  stable/12/usr.bin/ar/read.c
  stable/12/usr.bin/ar/write.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.bin/ar/ar.h
==============================================================================
--- stable/12/usr.bin/ar/ar.h	Mon Apr 29 18:28:34 2019	(r346901)
+++ stable/12/usr.bin/ar/ar.h	Mon Apr 29 18:34:11 2019	(r346902)
@@ -100,9 +100,11 @@ struct bsdar {
 	/*
 	 * Fields for the archive symbol table.
 	 */
-	uint32_t	  s_cnt;	/* current number of symbols. */
-	uint32_t	 *s_so;		/* symbol offset table. */
+	uint64_t	  s_cnt;	/* current number of symbols. */
+	uint64_t	 *s_so;		/* symbol offset table. */
+	uint64_t	  s_so_max;     /* maximum symbol offset. */
 	size_t		  s_so_cap;	/* capacity of so table buffer. */
+
 	char		 *s_sn;		/* symbol name table */
 	size_t		  s_sn_cap;	/* capacity of sn table buffer. */
 	size_t		  s_sn_sz;	/* current size of sn table. */

Modified: stable/12/usr.bin/ar/read.c
==============================================================================
--- stable/12/usr.bin/ar/read.c	Mon Apr 29 18:28:34 2019	(r346901)
+++ stable/12/usr.bin/ar/read.c	Mon Apr 29 18:34:11 2019	(r346902)
@@ -109,7 +109,8 @@ read_archive(struct bsdar *bsdar, char mode)
 			break;
 
 		/* Skip pseudo members. */
-		if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0)
+		if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0 ||
+		    strcmp(name, "/SYM64/") == 0)
 			continue;
 
 		if (bsdar->argc > 0) {

Modified: stable/12/usr.bin/ar/write.c
==============================================================================
--- stable/12/usr.bin/ar/write.c	Mon Apr 29 18:28:34 2019	(r346901)
+++ stable/12/usr.bin/ar/write.c	Mon Apr 29 18:34:11 2019	(r346902)
@@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$");
 #define _ARMAG_LEN 8		/* length of ar magic string */
 #define _ARHDR_LEN 60		/* length of ar header */
 #define _INIT_AS_CAP 128	/* initial archive string table size */
-#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
+#define _INIT_SYMOFF_CAP (256*(sizeof(uint64_t))) /* initial so table size */
 #define _INIT_SYMNAME_CAP 1024			  /* initial sn table size */
 #define _MAXNAMELEN_SVR4 15	/* max member name length in svr4 variant */
 #define _TRUNCATE_LEN 15	/* number of bytes to keep for member name */
@@ -557,6 +557,7 @@ write_cleanup(struct bsdar *bsdar)
 	free(bsdar->s_sn);
 	bsdar->as = NULL;
 	bsdar->s_so = NULL;
+	bsdar->s_so_max = 0;
 	bsdar->s_sn = NULL;
 }
 
@@ -613,7 +614,10 @@ write_objs(struct bsdar *bsdar)
 	struct archive_entry	*entry;
 	size_t s_sz;		/* size of archive symbol table. */
 	size_t pm_sz;		/* size of pseudo members */
-	int			 i, nr;
+	size_t w_sz;		/* size of words in symbol table */
+	uint64_t		 nr;
+	uint32_t		 nr32;
+	int			 i;
 
 	if (elf_version(EV_CURRENT) == EV_NONE)
 		bsdar_errc(bsdar, EX_SOFTWARE, 0,
@@ -628,9 +632,6 @@ write_objs(struct bsdar *bsdar)
 		if (strlen(obj->name) > _MAXNAMELEN_SVR4)
 			add_to_ar_str_table(bsdar, obj->name);
 		bsdar->rela_off += _ARHDR_LEN + obj->size + obj->size % 2;
-		if (bsdar->rela_off > UINT32_MAX)
-			bsdar_errc(bsdar, EX_SOFTWARE, 0,
-			    "Symbol table offset overflow");
 	}
 
 	/*
@@ -656,18 +657,31 @@ write_objs(struct bsdar *bsdar)
 	 *
 	 * absolute_offset = htobe32(relative_offset + size_of_pseudo_members)
 	 */
-
+	w_sz = sizeof(uint32_t);
 	if (bsdar->s_cnt != 0) {
 		s_sz = (bsdar->s_cnt + 1) * sizeof(uint32_t) + bsdar->s_sn_sz;
 		pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
 		if (bsdar->as != NULL)
 			pm_sz += _ARHDR_LEN + bsdar->as_sz;
-		for (i = 0; (size_t)i < bsdar->s_cnt; i++) {
-			if (*(bsdar->s_so + i) > UINT32_MAX - pm_sz)
-				bsdar_errc(bsdar, EX_SOFTWARE, 0,
-				    "Symbol table offset overflow");
-			*(bsdar->s_so + i) = htobe32(*(bsdar->s_so + i) +
-			    pm_sz);
+		/* Use the 64-bit word size format if necessary. */
+		if (bsdar->s_so_max > UINT32_MAX - pm_sz) {
+			w_sz = sizeof(uint64_t);
+			pm_sz -= s_sz;
+			s_sz = (bsdar->s_cnt + 1) * sizeof(uint64_t) +
+			    bsdar->s_sn_sz;
+			pm_sz += s_sz;
+			/* Convert to big-endian. */
+			for (i = 0; (size_t)i < bsdar->s_cnt; i++)
+				bsdar->s_so[i] =
+				    htobe64(bsdar->s_so[i] + pm_sz);
+		} else {
+			/*
+			 * Convert to big-endian and shuffle in-place to
+			 * the front of the allocation. XXX UB
+			 */
+			for (i = 0; (size_t)i < bsdar->s_cnt; i++)
+				((uint32_t *)(bsdar->s_so))[i] =
+				    htobe32(bsdar->s_so[i] + pm_sz);
 		}
 	}
 
@@ -689,16 +703,23 @@ write_objs(struct bsdar *bsdar)
 		if (entry == NULL)
 			bsdar_errc(bsdar, EX_SOFTWARE, 0,
 			    "archive_entry_new failed");
-		archive_entry_copy_pathname(entry, "/");
+		if (w_sz == sizeof(uint64_t))
+			archive_entry_copy_pathname(entry, "/SYM64/");
+		else
+			archive_entry_copy_pathname(entry, "/");
 		if ((bsdar->options & AR_D) == 0)
 			archive_entry_set_mtime(entry, time(NULL), 0);
-		archive_entry_set_size(entry, (bsdar->s_cnt + 1) *
-		    sizeof(uint32_t) + bsdar->s_sn_sz);
+		archive_entry_set_size(entry, (bsdar->s_cnt + 1) * w_sz +
+		    bsdar->s_sn_sz);
 		AC(archive_write_header(a, entry));
-		nr = htobe32(bsdar->s_cnt);
-		write_data(bsdar, a, &nr, sizeof(uint32_t));
-		write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) *
-		    bsdar->s_cnt);
+		if (w_sz == sizeof(uint64_t)) {
+			nr = htobe64(bsdar->s_cnt);
+			write_data(bsdar, a, &nr, sizeof(nr));
+		} else {
+			nr32 = htobe32((uint32_t)bsdar->s_cnt);
+			write_data(bsdar, a, &nr32, sizeof(nr32));
+		}
+		write_data(bsdar, a, bsdar->s_so, w_sz * bsdar->s_cnt);
 		write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
 		archive_entry_free(entry);
 	}
@@ -904,13 +925,15 @@ add_to_ar_sym_table(struct bsdar *bsdar, const char *n
 		bsdar->s_sn_sz = 0;
 	}
 
-	if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) {
+	if (bsdar->s_cnt * sizeof(uint64_t) >= bsdar->s_so_cap) {
 		bsdar->s_so_cap *= 2;
 		bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap);
 		if (bsdar->s_so == NULL)
 			bsdar_errc(bsdar, EX_SOFTWARE, errno, "realloc failed");
 	}
 	bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off;
+	if ((uint64_t)bsdar->rela_off > bsdar->s_so_max)
+		bsdar->s_so_max = (uint64_t)bsdar->rela_off;
 	bsdar->s_cnt++;
 
 	/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904291834.x3TIYBav045405>