summaryrefslogtreecommitdiff
path: root/usr.bin/ar
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2019-04-22 19:55:47 +0000
committerEd Maste <emaste@FreeBSD.org>2019-04-22 19:55:47 +0000
commit1dffcf9f2d7cb0e44a31fd7dde072c554e591d9d (patch)
tree45a5d893b3ce8cd08da6d4e39c9c70e2d8345485 /usr.bin/ar
parent6bbdbbb8308e13ccad711c01a6b0d6795d9faddf (diff)
downloadsrc-test2-1dffcf9f2d7cb0e44a31fd7dde072c554e591d9d.tar.gz
src-test2-1dffcf9f2d7cb0e44a31fd7dde072c554e591d9d.zip
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 MFC after: 10 days MFC with: r346079 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D20007
Notes
Notes: svn path=/head/; revision=346582
Diffstat (limited to 'usr.bin/ar')
-rw-r--r--usr.bin/ar/write.c37
1 files changed, 18 insertions, 19 deletions
diff --git a/usr.bin/ar/write.c b/usr.bin/ar/write.c
index 66d776e5c80c..16f255b432a0 100644
--- a/usr.bin/ar/write.c
+++ b/usr.bin/ar/write.c
@@ -616,6 +616,7 @@ write_objs(struct bsdar *bsdar)
size_t pm_sz; /* size of pseudo members */
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)
@@ -669,15 +670,18 @@ write_objs(struct bsdar *bsdar)
s_sz = (bsdar->s_cnt + 1) * sizeof(uint64_t) +
bsdar->s_sn_sz;
pm_sz += s_sz;
- }
-
- for (i = 0; (size_t)i < bsdar->s_cnt; i++) {
- if (w_sz == sizeof(uint32_t))
- bsdar->s_so[i] =
- htobe32(bsdar->s_so[i] + pm_sz);
- else
+ /* 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);
}
}
@@ -708,19 +712,14 @@ write_objs(struct bsdar *bsdar)
archive_entry_set_size(entry, (bsdar->s_cnt + 1) * w_sz +
bsdar->s_sn_sz);
AC(archive_write_header(a, entry));
- if (w_sz == sizeof(uint32_t))
- nr = (uint64_t)htobe32((uint32_t)bsdar->s_cnt);
- else
+ if (w_sz == sizeof(uint64_t)) {
nr = htobe64(bsdar->s_cnt);
- write_data(bsdar, a, &nr, w_sz);
- if (w_sz == sizeof(uint64_t))
- write_data(bsdar, a, bsdar->s_so, sizeof(uint64_t) *
- bsdar->s_cnt);
- else
- for (i = 0; (size_t)i < bsdar->s_cnt; i++)
- write_data(bsdar, a,
- (uint32_t *)&bsdar->s_so[i],
- sizeof(uint32_t));
+ 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);
}