/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* 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
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
*/
#include <sys/sendfile.h>
#include "inc.h"
#include "gelf.h"
/*
* List of archive members, accessed globally by cmd and file.
*/
/*
* Type used to manage string tables. Archives can have two of these:
*
* sym_strtbl: String table included at the end of the symbol table
* archive member, following the offset array.
*
* long_strtbl: String table used to hold member names that exceed 15
* characters in length, found in the long names archive member.
*/
typedef struct {
} ARSTRTBL;
/*
* Name and file descriptor used when creating a new archive.
* If this variable references an open file when exit_cleanup()
* executes, it will close and remove the file, preventing incomplete
* temporary files from being left behind in the case of a failure
* or interruption.
*/
static struct {
} ar_outfile;
/*
* 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 (member data) have the proper alignment, we can access them
* directly. If the data alignment is wrong, libelf "slides" them over the
* archive header to correct the misalignment. 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.
*/
/*
* Forward Declarations
*/
static size_t mklong_tab();
static const char *make_tmpname(const char *);
static void savelongname(ARFILE *);
static void savename(char *);
static char *trimslash(char *s);
size_t);
/*
* Function to be called on exit to clean up incomplete new archive.
*/
static void
exit_cleanup(void)
{
/* Both of these system calls are Async-Signal-Safe */
}
}
/*
* Open an existing archive.
*/
int
{
int fd;
elf_errmsg(-1));
exit(1);
}
/* archive does not exist yet, may have to create one */
return (fd);
} else {
/* problem other than "does not exist" */
exit(1);
}
}
cmd = ELF_C_READ;
exit(1);
}
return (fd);
}
/*
* Given a value, and a pad alignment, return the number of bytes
* required to pad the value to the next alignment boundary.
*/
static size_t
{
size_t r;
r = n % align;
if (r)
r = align - r;
return (r);
}
/*
* If the current archive item is an ELF 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 member header.
* 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.
*/
static void
{
/* ar(1) only pads objects, so bail if not looking at one */
return;
/*
* libelf always puts the section header array at the end
* of the object, and all of our compilers and other tools
* use libelf 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 PADSZ bytes, then
* we've found the end, and the difference is padding (We assume
* that no ELF section can fit into PADSZ bytes).
*/
return;
/*
* If the extent exceeds the end of the archive member
* (negative padding), then we don't know what is going on
* and simply leave things alone.
*/
return;
/*
* 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
* PADSZ bytes of ar_size, then this is the end of the object.
*/
do {
if (scn) {
size_t t;
if (t > extent)
extent = t;
}
}
} while (scn);
return;
}
/*
* Now, test the padding. We only act on padding in the range
* (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 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 (file->ar_contents) {
while (cnt--) {
if (*p++ != '\n') { /* No padding */
padding = 0;
break;
}
}
}
/* Remove the padding from the size */
}
}
/*
* Each call to getfile() returns the next unread archive member
* from the archive opened by getaf(). Returns NULL if no more
* archive members are left.
*/
ARFILE *
{
if (fd == -1)
return (NULL); /* the archive doesn't exist */
while (mem_header == NULL) {
return (NULL); /* archive is empty or have hit end */
exit(1);
}
/* Ignore special members like the symbol and string tables */
mem_header = NULL;
}
}
/*
* NOTE:
* The mem_header->ar_name[] is set to a NULL string
* if the archive member header has some error.
* (See elf_getarhdr() man page.)
* It is set to NULL for example, the ar command reads
* the archive files created by SunOS 4.1 system.
* See c block comment in cmd.c, "Incompatible Archive Header".
*/
== NULL) {
exit(1);
}
== NULL) {
exit(1);
}
while (!isspace(*tmp_rawname) &&
file_rawname++;
tmp_rawname++;
}
if (!(*tmp_rawname == '\0'))
*file_rawname = '\0';
/* reverse logic */
== NULL) {
if (ptr != 0) {
exit(1);
}
}
}
return (file);
}
/*
* Allocate a new archive member descriptor and add it to the list.
*/
ARFILE *
newfile(void)
{
if (count == 0) {
== NULL) {
exit(1);
}
}
count--;
if (listhead)
else
return (fileptr);
}
static char *
trimslash(char *s)
{
}
char *
trim(char *s)
{
;
while (p1 > s) {
if (*--p1 != '/')
break;
*p1 = 0;
}
p2 = s;
if (*p1 == '/')
return (p2);
}
/*
* Find all the global symbols exported by ELF archive members, and
* build a list associating each one with the archive member that
* provides it.
*
* exit:
* *symlist is set to the list of symbols. If any ELF object was
* found, *found_obj is set to TRUE (1). Returns the number of symbols
* located.
*/
static size_t
{
int newfd;
int class = 0;
newfd = 0;
/* determine if file is coming from the archive or not */
/*
* I can use the saved elf descriptor.
*/
#ifdef _LP64
/*
* The archive member header ar_size field is 10
* decimal digits, sufficient to represent a 32-bit
* value, but not a 64-bit one. Hence, we reject
* attempts to insert a member larger than 4GB.
*
* One obvious way to extend the format without altering
* the ar_hdr struct is to use the same mechanism used
* for ar_name: Put the size string into the long name
* string table and write a string /xxx into ar_size,
* where xxx is the string table offset.
*
* At the time of this writing (June 2010), the largest
* relocatable objects are measured in 10s or 100s
* of megabytes, so we still have many years to go
* before this becomes limiting. By that time, it may
* turn out that a completely new archive format is
* a better solution, as the current format has many
* warts and inefficiencies. In the meantime, we
* won't burden the current implementation with support
* for a bandaid feature that will have little use.
*/
fptr->ar_pathname);
num_errs++;
continue;
}
#endif
if ((newfd =
num_errs++;
continue;
}
ELF_C_READ, (Elf *)0)) == 0) {
newfd = 0;
num_errs++;
continue;
}
if (newfd) {
newfd = 0;
}
continue;
}
} else {
exit(1);
}
} else if (class == ELFCLASS32)
} else {
elf_errmsg(-1));
}
num_errs++;
if (newfd) {
newfd = 0;
}
continue;
}
else
elf_errmsg(-1));
num_errs++;
if (newfd) {
newfd = 0;
}
continue;
}
data = 0;
else
elf_errmsg(-1));
num_errs++;
if (newfd) {
newfd = 0;
}
continue;
}
fptr->ar_pathname);
else
if (newfd) {
newfd = 0;
}
num_errs++;
continue;
}
/* loop through sections to find symbol table */
scn = 0;
/* BEGIN CSTYLED */
elf_errmsg(-1));
else
elf_errmsg(-1));
/* END CSTYLED */
if (newfd) {
newfd = 0;
}
num_errs++;
continue;
}
*found_obj = 1;
&num_errs) == -1) {
if (newfd) {
newfd = 0;
}
continue;
}
}
}
}
mem_offset++;
if (newfd) {
newfd = 0;
}
}
if (num_errs)
exit(1);
if (found_obj) {
if (nsyms == 0) {
/*
* It is possible, though rare, to have ELF objects
* that do not export any global symbols. Presumably
* such objects operate via their .init/.fini
* sections. In this case, we produce an empty
* symbol table, so that applications that rely
* on a successful call to elf_getarsym() to determine
* if ELF objects are present will succeed. To do this,
* we require a small empty symbol string table.
*/
} else {
/*
* Historical behavior is to pad string tables
* to a multiple of 4.
*/
}
}
return (nsyms);
}
/*
* Output a member header.
*/
/*ARGSUSED*/
static void
{
int len;
/*
* If snprintf() reports that it needed more space than we gave
* it, it means that the caller fed us a long name, which is a
* fatal internal error.
*/
exit(1);
}
/*
* We inject inter-member padding to ensure that ELF object
* member data is aligned on PADSZ. If this is a debug build,
* verify that the computations were right.
*/
}
/*
* Write the archive symbol table member to the output archive file.
*
* note:
* sizeofmembers() must have been called to establish member offset
* and padding values before writesymtab() is used.
*/
static void
{
size_t i, j;
/*
* We require a buffer large enough to hold a symbol table count,
* plus one offset for each symbol.
*/
exit(1);
}
if (!j) {
j = SYMCHUNK;
}
}
}
/*
* Grow the size of the given string table so that there is room
* for at least need bytes.
*
* entry:
* strtbl - String table to grow
* need - Amount of space required by caller
*/
static void
{
/*
* On 32-bit systems, we require a larger integer type in order
* to avoid overflow and wraparound when doing our computations.
*/
return;
/*
* Detect 32-bit system. We might usually do this with the preprocessor,
* but it can serve as a predicate in tests that also apply to 64-bit
* systems.
*/
/*
* The symbol string table can be larger than 32-bits on a 64-bit
* system. However, the long name table must stay below that limit.
* The reason for this is that there is not enough room in the ar_name
* field of the member header to represent 64-bit offsets.
*/
/*
* If request is larger than 4GB and we can't do it because we
* are a 32-bit program, or because the table is format limited,
* we can go no further.
*/
goto limit_fail;
/* Default starting size */
/*
* Our strategy is to double the size until we find a size that
* exceeds the request. However, if this table cannot exceed 4GB,
* then once we exceed 2GB, we switch to a strategy of taking the
* current request and rounding it up to STRTBL_INITSZ.
*/
/*
* If we are so close to the line that this small
* increment exceeds 4GB, give it up.
*/
goto limit_fail;
break;
}
size64 *= 2;
}
exit(1);
}
return;
/*
* Control comes here if we are unable to allocate more than 4GB of
* memory for the string table due to one of the following reasons:
*
* - A 32-bit process is attempting to be larger than 4GB
*
* - A 64-bit process is attempting to grow the long names string
* table beyond the ar format limit of 32-bits.
*/
if (sys32)
else
exit(1);
}
/*
* Add the specified number of pad characters to the end of the
* given string table.
*
* entry:
* strtbl - String table to pad
* n - # of pad characters to add
* ch - Pad character to use
*/
static void
{
if (n == 0)
return;
strtbl_alloc(strtbl, n);
while (n--)
}
/*
* Enter a symbol name into the symbol string table.
*/
static void
{
}
/*
* Prepare an archive member with a long (>15 characters) name for
* the output archive.
*
* entry:
* fptr - pointer to archive member with long name
*
* exit:
* The long name is entered into the long name string table,
* and fptr->ar_name has been replaced with the special /xxx
* name used to indicate that the real name is in the string table
* at offset xxx.
*/
static void
{
char *p;
/* Size of new item to add */
/* Ensure there's room */
/*
* Generate the index string to be written into the member header
*
* This will not overflow the ar_name field because that field is
* 16 characters in size, and a 32-bit unsigned value can be formatted
* in 10 characters. Allowing a character for the leading '/', and one
* for the NULL termination, that leaves us with 4 extra spaces.
*/
/*
* Enter long name into reserved spot, terminated with a slash
* and a newline character.
*/
p += len;
*p++ = '/';
*p++ = '\n';
}
/*
* Determine if the archive we're about to write will exceed the
* 32-bit limit of 4GB.
*
* entry:
* mksymtab() and mklong_tab() have been called to set up
* the string tables.
*
* exit:
* Returns TRUE (1) if the 64-bit symbol table is needed, and
* FALSE (0) otherwise.
*
*/
static int
{
/*
* If there are more than 4GB symbols, we have to use
* the 64-bit form. Note that longnames cannot exceed 4GB
* because that symbol table is limited to a length of 4GB by
* the archive format.
*/
if (nsyms > 0xffffffff)
return (1);
/*
* Make a worst case estimate for the size of the resulting
* archive by assuming full padding between members.
*/
if (longnames)
if (found_obj)
if (size > 0xffffffff)
return (1);
if (size > 0xffffffff)
return (1);
}
/* 32-bit symbol table will suffice */
return (0);
}
void
{
int new_archive = 0;
int found_obj = 0;
int fd;
int is_elf;
/*
* Gather the list of symbols and associate each one to the
* ARFILE descriptor of the object it belongs to. At the same
* time, tag each ELF object with the appropriate F_CLASSxx
* flag.
*/
/* Generate the string table for long member names */
longnames = mklong_tab();
/*
* Will this archive exceed 4GB? If we're a 32-bit process, we can't
* do it. If we're a 64-bit process, then we'll have to use a
* 64-bit symbol table.
*/
#ifdef _LP64
symtbl_eltsize = 8;
#else
exit(1);
#endif
}
/*
* If the user requested it, use the 64-bit symbol table even if
* a 32-bit one would suffice. 32-bit tables are more portable and
* take up less room, so this feature is primarily for testing.
*/
symtbl_eltsize = 8;
/*
* If the first non-special archive member is an ELF object, then we
* need to arrange for its data to have an alignment of PADSZ. The
* preceeding special member will be the symbol table, or the long
* name string table. We pad the string table that precedes the
* ELF member in order to achive the desired alignment.
*/
if (found_obj) {
}
}
if (longnames > 0) {
if (is_elf) {
}
}
/*
* For each user visible (non-special) archive member, determine
* the header offset, and the size of any required padding.
*/
(void) sizeofmembers(arsize);
/*
* Is this a new archive, or are we updating an existing one?
*
* A subtlety here is that POSIX says we are not supposed
* to replace a non-writable file. The only 100% reliable test
* against this is to open the file for non-destructive
* write access. If the open succeeds, we are clear to
* replace it, and if not, then the error generated is
* the error we need to report.
*/
exit(1);
}
new_archive = 1;
}
} else {
/* Capture mode and owner information to apply to replacement */
exit(1);
}
new_archive = 0;
}
/*
* Register exit handler function to clean up after us if we exit
* before completing the new archive. atexit() is defined as
* only being able to fail due to memory exhaustion.
*/
if (atexit(exit_cleanup) != 0) {
exit(1);
}
/*
* If a new archive, create it in place. If updating an archive,
* create the replacement under a temporary name and then rename it
* into place.
*/
exit(1);
}
/* Output magic string */
/*
* The symbol table member is always first if present. Note that
* writesymtab() uses the member offsets computed by sizeofmembers()
* above.
*/
if (found_obj)
if (longnames) {
}
/*
* The accuracy of the symbol table depends on our having calculated
* the size of the archive accurately to this point. If this is a
* debug build, verify it.
*/
#ifndef XPG4
}
#endif
/*
* Fill pad_bytes array with newline characters. This array
* is used to supply padding bytes at the end of ELF objects.
* There can never be more tha PADSZ such bytes, so this number
* will always suffice.
*/
/*
* We computed the expected offset for each ELF member and
* used those offsets to fill the symbol table. If this is
* a debug build, verify that the computed offset was right.
*/
/*
* NOTE:
* The mem_header->ar_name[] is set to a NULL string
* if the archive member header has some error.
* (See elf_getarhdr() man page.)
* It is set to NULL for example, the ar command reads
* the archive files created by SunOS 4.1 system.
* See c block comment in cmd.c, "Incompatible Archive Header".
*/
}
/*
* The file doesn't come from the archive, and is
* therefore not already in memory(fptr->ar_contents)
* so open it and do a direct file-to-file transfer of
* its contents. We use the sendfile() system call
* to make the kernel do the transfer, so we don't have
* to buffer data in process, and we trust that the
* kernel will use an optimal transfer strategy.
*/
exit(1);
}
exit(1);
}
off = 0;
exit(2);
}
} else {
/* Archive member is in memory. Write it out */
}
/*
* All archive members are padded to at least a boundary of 2.
* The expression ((fptr->ar_size & 0x1) != 0) yields 1 for
* odd boundaries, and 0 for even ones. To this, we add
* whatever padding is needed for ELF objects.
*/
if (pad_cnt > 0)
}
/*
* All archive output is done.
*/
exit(1);
}
/*
* If updating an existing archive, rename the new version on
* top of the original.
*/
if (!new_archive) {
/*
* Prevent the replacement of the original archive from
* being interrupted, to lower the possibility of an
* interrupt destroying a pre-existing archive.
*/
exit(1);
}
}
}
/*
* Examine all the archive members, enter any member names longer than
* 15 characters into the long name string table, and count the number
* of names found.
*
* Returns the size of the resulting archive member, including the
* member header.
*/
static size_t
mklong_tab(void)
{
longnames++;
}
}
/* round up table that keeps the long filenames */
if (longnames > 0)
return (longnames);
}
/*
* Write 32/64-bit words into buffer in archive symbol table
* standard byte order (MSB).
*/
static char *
{
*cp++ = n >> 24;
*cp++ = n >> 16;
*cp++ = n >> 8;
*cp++ = n & 255;
return (cp);
}
static char *
{
*cp++ = n >> 56;
*cp++ = n >> 48;
*cp++ = n >> 40;
*cp++ = n >> 32;
*cp++ = n >> 24;
*cp++ = n >> 16;
*cp++ = n >> 8;
*cp++ = n & 255;
return (cp);
}
static int
{
int counter;
int str_shtype;
char *symname;
static int syms_left = 0;
else
(*num_errs)++;
return (-1);
}
if (no_of_symbols == -1) {
return (-1);
}
if (str_shtype == -1) {
else
(*num_errs)++;
return (-1);
}
/* This test must happen before testing the string table. */
if (no_of_symbols == 1)
return (0); /* no symbols; 0th symbol is the non-symbol */
if (str_shtype != SHT_STRTAB) {
fname);
else
return (0);
}
str_data = 0;
fname);
else
return (0);
}
fname);
else
return (0);
}
sym_data = 0;
else
return (0);
}
/* start at 1, first symbol entry is ignored */
if (!syms_left) {
* sizeof (ARFILEP));
exit(1);
}
if (nextsym)
else
}
nextsym++;
syms_left--;
(*nsyms)++;
/* symbol table string table */
}
}
return (0);
}
/*
* Get the output file size
*/
static size_t
{
sum++;
/*
* If the current item, and the next item are both ELF
* objects, then add padding to current item so that the
* data in the next item will have PADSZ alignment.
*
* In any other case, set the padding to 0. If the
* item comes from another archive, it may be carrying
* a non-zero padding value from that archive that does
* not apply to the one we are about to build.
*/
} else {
fptr->ar_padding = 0;
}
}
return (sum);
}
/*
* Compute the size of the symbol table archive member.
*
* entry:
* nsyms - # of symbols in the table
* found_obj - TRUE if the archive contains any ELF objects
* eltsize - Size of the integer type to use for the symbol
* table. 4 for 32-bit tables, and 8 for 64-bit tables.
*/
static size_t
{
if (found_obj) {
/* Member header, symbol count, and one slot per symbol */
}
return (sum);
}
static void
exit(2);
}
}
static const char *
/*
* If there is a path prefix in front of the filename, we
* want to put the temporary file in the same directory.
* Determine the length of the path.
*/
exit(1);
}
if (prefix_cnt > 0)
return (tmpname);
}