* objcopy.c (keep_specific_list, privatize_specific_list,

weaken_specific_list): New variables.
        (keep_symbols): Removed.
        (add_specific_symbol): New function from the carcas of
        add_strip_symbol.  Takes a list as an argument.
        (is_specified_symbol): Likewise from is_strip_symbol.
        (filter_symbols): Honor the new privatize and weaken lists.
        Optimize bfd_asymbol_name handling.
        (copy_object, copy_options, copy_usage): Add privatize-symbol &
        weaken-symbol options.

        * objcopy.1, binutils.texi: Update docs.
This commit is contained in:
Richard Henderson 1997-10-09 04:34:59 +00:00
parent 2875c6c685
commit 8d2e72a1c8
4 changed files with 372 additions and 107 deletions

View File

@ -1,8 +1,24 @@
Wed Oct 8 21:19:11 1997 Richard Henderson <rth@cygnus.com>
* objcopy.c (keep_specific_list, privatize_specific_list,
weaken_specific_list): New variables.
(keep_symbols): Removed.
(add_specific_symbol): New function from the carcas of
add_strip_symbol. Takes a list as an argument.
(is_specified_symbol): Likewise from is_strip_symbol.
(filter_symbols): Honor the new privatize and weaken lists.
Optimize bfd_asymbol_name handling.
(copy_object, copy_options, copy_usage): Add privatize-symbol &
weaken-symbol options.
* objcopy.1, binutils.texi: Update docs.
Sun Oct 5 09:05:44 1997 Frank Ch. Eigler <fche@cygnus.com>
* objdump.c (disassemble_data): Add "0x" prefix for
symbol-offsets in disassembly. Make "--prefix-addresses"
disassembly adjust to mixed-length instructions.
* objdump.c (disassemble_data): Make "--prefix-addresses"
disassembly adjust to mixed-length instructions.
(objdump_print_addr_with_sym): Add "0x" prefix for hexadecimal
symbol-offsets in disassembly.
Fri Oct 3 12:04:25 1997 Ian Lance Taylor <ian@cygnus.com>

View File

@ -816,6 +816,8 @@ objcopy [ -F @var{bfdname} | --target=@var{bfdname} ]
[ -S | --strip-all ] [ -g | --strip-debug ]
[ -K @var{symbolname} | --keep-symbol=@var{symbolname} ]
[ -N @var{symbolname} | --strip-symbol=@var{symbolname} ]
[ -P @var{symbolname} | --privatize-symbol=@var{symbolname} ]
[ -W @var{symbolname} | --weaken-symbol=@var{symbolname} ]
[ -x | --discard-all ] [ -X | --discard-locals ]
[ -b @var{byte} | --byte=@var{byte} ]
[ -i @var{interleave} | --interleave=@var{interleave} ]
@ -910,8 +912,16 @@ be given more than once.
@item -N @var{symbolname}
@itemx --strip-symbol=@var{symbolname}
Do not copy symbol @var{symbolname} from the source file. This option
may be given more than once, and may be combined with strip options
other than @code{-K}.
may be given more than once.
@item -P @var{symbolname}
@itemx --privatize-symbol=@var{symbolname}
Make symbol @var{symbolname} local to the file, so that it is not
visible externally. This option may be given more than once.
@item -W @var{symbolname}
@itemx --weaken-symbol=@var{symbolname}
Make symbol @var{symbolname} weak. This option may be given more than once.
@item -x
@itemx --discard-all

View File

@ -24,6 +24,8 @@ objcopy \- copy and translate object files
.RB "[\|" \-\-strip\-unneeded\fR "\|]"
.RB "[\|" \-K\ \fIsymbolname\fR\ |\ \fB\-\-keep\-symbol=\fIsymbolname\fR "\|]"
.RB "[\|" \-N\ \fIsymbolname\fR\ |\ \fB\-\-strip\-symbol=\fIsymbolname\fR "\|]"
.RB "[\|" \-P\ \fIsymbolname\fR\ |\ \fB\-\-privatize\-symbol=\fIsymbolname\fR "\|]"
.RB "[\|" \-W\ \fIsymbolname\fR\ |\ \fB\-\-weaken\-symbol=\fIsymbolname\fR "\|]"
.RB "[\|" \-x\fR\ |\ \fB\-\-discard\-all\fR "\|]"
.RB "[\|" \-X\fR\ |\ \fB\-\-discard\-locals\fR "\|]"
.RB "[\|" \-b\ \fIbyte\fR\ |\ \fB\-\-byte=\fIbyte\fR "\|]"
@ -139,8 +141,14 @@ may be given more than once.
.TP
.B \-N \fIsymbolname\fR, \fB\-\-strip\-symbol=\fIsymbolname
Do not copy symbol \fIsymbolname\fP from the source file. This option
may be given more than once, and may be combined with strip options
other than \fB\-K\fR.
may be given more than once.
.TP
.B \-P \fIsymbolname\fR, \fB\-\-privatize\-symbol=\fIsymbolname
Make symbol \fIsymbolname\fP local to the file, so that it is not
visible externally. This option may be given more than once.
.TP
.B \-W \fIsymbolname\fR, \fB\-\-weaken\-symbol=\fIsymbolname
Make symbol \fIsymbolname\fP weak. This option may be given more than once.
.TP
.B \-x\fR, \fB \-\-discard\-all
Do not copy non-global symbols from the source file.

View File

@ -1,5 +1,5 @@
/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU Binutils.
@ -25,6 +25,16 @@
#include "budbg.h"
#include <sys/stat.h>
#ifdef HAVE_GOOD_UTIME_H
#include <utime.h>
#else /* ! HAVE_GOOD_UTIME_H */
#ifdef HAVE_UTIMES
#include <sys/time.h>
#endif /* HAVE_UTIMES */
#endif /* ! HAVE_GOOD_UTIME_H */
static void copy_usage PARAMS ((FILE *, int));
static void strip_usage PARAMS ((FILE *, int));
static flagword parse_flags PARAMS ((const char *));
static struct section_list *find_section_list PARAMS ((const char *, boolean));
static void setup_section PARAMS ((bfd *, asection *, PTR));
@ -35,9 +45,19 @@ static void add_strip_symbol PARAMS ((const char *));
static boolean is_strip_symbol PARAMS ((const char *));
static boolean is_strip_section PARAMS ((bfd *, asection *));
static unsigned int filter_symbols
PARAMS ((bfd *, asymbol **, asymbol **, long));
PARAMS ((bfd *, bfd *, asymbol **, asymbol **, long));
static void mark_symbols_used_in_relocations PARAMS ((bfd *, asection *, PTR));
static void filter_bytes PARAMS ((char *, bfd_size_type *));
static boolean write_debugging_info PARAMS ((bfd *, PTR, long *, asymbol ***));
static void copy_object PARAMS ((bfd *, bfd *));
static void copy_archive PARAMS ((bfd *, bfd *, const char *));
static void copy_file
PARAMS ((const char *, const char *, const char *, const char *));
static int simple_copy PARAMS ((const char *, const char *));
static int smart_rename PARAMS ((const char *, const char *));
static void set_times PARAMS ((const char *, const struct stat *));
static int strip_main PARAMS ((int, char **));
static int copy_main PARAMS ((int, char **));
#define nonfatal(s) {bfd_nonfatal(s); status = 1; return;}
@ -138,6 +158,14 @@ static struct section_add *add_sections;
static boolean convert_debugging = false;
/* Whether to change the leading character in symbol names. */
static boolean change_leading_char = false;
/* Whether to remove the leading character from global symbol names. */
static boolean remove_leading_char = false;
/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
#define OPTION_ADD_SECTION 150
@ -145,13 +173,16 @@ static boolean convert_debugging = false;
#define OPTION_ADJUST_VMA (OPTION_ADJUST_START + 1)
#define OPTION_ADJUST_SECTION_VMA (OPTION_ADJUST_VMA + 1)
#define OPTION_ADJUST_WARNINGS (OPTION_ADJUST_SECTION_VMA + 1)
#define OPTION_DEBUGGING (OPTION_ADJUST_WARNINGS + 1)
#define OPTION_CHANGE_LEADING_CHAR (OPTION_ADJUST_WARNINGS + 1)
#define OPTION_DEBUGGING (OPTION_CHANGE_LEADING_CHAR + 1)
#define OPTION_GAP_FILL (OPTION_DEBUGGING + 1)
#define OPTION_NO_ADJUST_WARNINGS (OPTION_GAP_FILL + 1)
#define OPTION_PAD_TO (OPTION_NO_ADJUST_WARNINGS + 1)
#define OPTION_SET_SECTION_FLAGS (OPTION_PAD_TO + 1)
#define OPTION_REMOVE_LEADING_CHAR (OPTION_PAD_TO + 1)
#define OPTION_SET_SECTION_FLAGS (OPTION_REMOVE_LEADING_CHAR + 1)
#define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1)
#define OPTION_STRIP_UNNEEDED (OPTION_SET_START + 1)
#define OPTION_WEAKEN (OPTION_STRIP_UNNEEDED + 1)
/* Options to handle if running as "strip". */
@ -166,6 +197,7 @@ static struct option strip_options[] =
{"keep-symbol", required_argument, 0, 'K'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"preserve-dates", no_argument, 0, 'p'},
{"remove-section", required_argument, 0, 'R'},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
@ -187,6 +219,7 @@ static struct option copy_options[] =
{"adjust-section-vma", required_argument, 0, OPTION_ADJUST_SECTION_VMA},
{"adjust-warnings", no_argument, 0, OPTION_ADJUST_WARNINGS},
{"byte", required_argument, 0, 'b'},
{"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR},
{"debugging", no_argument, 0, OPTION_DEBUGGING},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
@ -201,6 +234,9 @@ static struct option copy_options[] =
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
{"pad-to", required_argument, 0, OPTION_PAD_TO},
{"preserve-dates", no_argument, 0, 'p'},
{"privatize-symbol", required_argument, 0, 'P'},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
{"set-start", required_argument, 0, OPTION_SET_START},
@ -211,12 +247,13 @@ static struct option copy_options[] =
{"target", required_argument, 0, 'F'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
{0, no_argument, 0, 0}
};
/* IMPORTS */
extern char *program_name;
extern char *program_version;
/* This flag distinguishes between strip and objcopy:
1 means this is 'strip'; 0 means this is 'objcopy'.
@ -230,22 +267,25 @@ copy_usage (stream, exit_status)
int exit_status;
{
fprintf (stream, "\
Usage: %s [-vVSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\
Usage: %s [-vVSpgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\
[-R section] [-i interleave] [--interleave=interleave] [--byte=byte]\n\
[--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
[--strip-all] [--strip-debug] [--strip-unneeded] [--discard-all]\n\
[--discard-locals] [--debugging] [--remove-section=section]\n",
program_name);
fprintf (stream, "\
[--gap-fill=val] [--pad-to=address]\n\
[--gap-fill=val] [--pad-to=address] [--preserve-dates]\n\
[--set-start=val] [--adjust-start=incr]\n\
[--adjust-vma=incr] [--adjust-section-vma=section{=,+,-}val]\n\
[--adjust-warnings] [--no-adjust-warnings]\n\
[--set-section-flags=section=flags] [--add-section=sectionname=filename]\n\
[--keep-symbol symbol] [-K symbol] [--strip-symbol symbol] [-N symbol]\n\
[--verbose] [--version] [--help]\n\
in-file [out-file]\n");
[--privatize-symbol symbol] [-P symbol] [--weaken-symbol symbol]\n\
[-W symbol] [--change-leading-char] [--remove-leading-char] [--weaken]\n\
[--verbose] [--version] [--help] in-file [out-file]\n");
list_supported_targets (program_name, stream);
if (exit_status == 0)
fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
exit (exit_status);
}
@ -255,14 +295,16 @@ strip_usage (stream, exit_status)
int exit_status;
{
fprintf (stream, "\
Usage: %s [-vVsSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-R section]\n\
Usage: %s [-vVsSpgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-R section]\n\
[--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
[--strip-all] [--strip-debug] [--strip-unneeded] [--discard-all]\n\
[--discard-locals] [--keep-symbol symbol] [-K symbol]\n\
[--strip-symbol symbol] [-N symbol] [--remove-section=section]\n\
[--verbose] [--version] [--help] file...\n",
[-o file] [--preserve-dates] [--verbose] [--version] [--help] file...\n",
program_name);
list_supported_targets (program_name, stream);
if (exit_status == 0)
fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
exit (exit_status);
}
@ -348,44 +390,48 @@ struct symlist
struct symlist *next;
};
/* List of symbols to strip. */
/* List of symbols to strip, keep, privatize, and weaken. */
static struct symlist *strip_specific_list = NULL;
static struct symlist *keep_specific_list = NULL;
static struct symlist *privatize_specific_list = NULL;
static struct symlist *weaken_specific_list = NULL;
/* If this is false, we strip the symbols in strip_specific_list.
Otherwise, we keep only the symbols in the list. */
/* If this is true, we weaken global symbols (set BSF_WEAK). */
static boolean keep_symbols = false;
static boolean weaken = false;
/* Add a symbol to strip_specific_list. */
static void
add_strip_symbol (name)
add_specific_symbol (name, list)
const char *name;
struct symlist **list;
{
struct symlist *tmp_list;
tmp_list = (struct symlist *) xmalloc (sizeof (struct symlist));
tmp_list->name = name;
tmp_list->next = strip_specific_list;
strip_specific_list = tmp_list;
tmp_list->next = *list;
*list = tmp_list;
}
/* See whether a symbol should be stripped or kept based on
strip_specific_list and keep_symbols. */
static boolean
is_strip_symbol (name)
is_specified_symbol (name, list)
const char *name;
struct symlist *list;
{
struct symlist *tmp_list;
for (tmp_list = strip_specific_list; tmp_list; tmp_list = tmp_list->next)
for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
{
if (strcmp (name, tmp_list->name) == 0)
return keep_symbols ? false : true;
return true;
}
return keep_symbols;
return false;
}
/* See if a section is being removed. */
@ -416,8 +462,9 @@ is_strip_section (abfd, sec)
Return the number of symbols to print. */
static unsigned int
filter_symbols (abfd, osyms, isyms, symcount)
filter_symbols (abfd, obfd, osyms, isyms, symcount)
bfd *abfd;
bfd *obfd;
asymbol **osyms, **isyms;
long symcount;
{
@ -428,11 +475,43 @@ filter_symbols (abfd, osyms, isyms, symcount)
{
asymbol *sym = from[src_count];
flagword flags = sym->flags;
const char *name = bfd_asymbol_name (sym);
int keep;
if (change_leading_char
&& (bfd_get_symbol_leading_char (abfd)
!= bfd_get_symbol_leading_char (obfd))
&& (bfd_get_symbol_leading_char (abfd) == '\0'
|| (name[0] == bfd_get_symbol_leading_char (abfd))))
{
if (bfd_get_symbol_leading_char (obfd) == '\0')
name = bfd_asymbol_name (sym) = name + 1;
else
{
char *n;
n = xmalloc (strlen (name) + 2);
n[0] = bfd_get_symbol_leading_char (obfd);
if (bfd_get_symbol_leading_char (abfd) == '\0')
strcpy (n + 1, name);
else
strcpy (n + 1, name + 1);
name = bfd_asymbol_name (sym) = n;
}
}
if (remove_leading_char
&& ((flags & BSF_GLOBAL) != 0
|| (flags & BSF_WEAK) != 0
|| bfd_is_und_section (bfd_get_section (sym))
|| bfd_is_com_section (bfd_get_section (sym)))
&& name[0] == bfd_get_symbol_leading_char (abfd))
name = bfd_asymbol_name (sym) = name + 1;
if ((flags & BSF_KEEP) != 0) /* Used in relocation. */
keep = 1;
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| bfd_is_und_section (bfd_get_section (sym))
|| bfd_is_com_section (bfd_get_section (sym)))
keep = strip_symbols != strip_unneeded;
@ -446,22 +525,39 @@ filter_symbols (abfd, osyms, isyms, symcount)
&& (discard_locals != locals_start_L
|| ! bfd_is_local_label (abfd, sym))));
if (keep && is_strip_symbol (bfd_asymbol_name (sym)))
if (keep && is_specified_symbol (name, strip_specific_list))
keep = 0;
if (!keep && is_specified_symbol (name, keep_specific_list))
keep = 1;
if (keep && is_strip_section (abfd, bfd_get_section (sym)))
keep = 0;
if (keep && (flags & BSF_GLOBAL) != 0
&& (weaken || is_specified_symbol (name, weaken_specific_list)))
{
sym->flags &=~ BSF_GLOBAL;
sym->flags |= BSF_WEAK;
}
if (keep && (flags & (BSF_GLOBAL | BSF_WEAK))
&& is_specified_symbol (name, privatize_specific_list))
{
sym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
sym->flags |= BSF_LOCAL;
}
if (keep)
to[dst_count++] = sym;
}
to[dst_count] = NULL;
return dst_count;
}
/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long.
Adjust *SIZE. */
void
static void
filter_bytes (memhunk, size)
char *memhunk;
bfd_size_type *size;
@ -514,7 +610,8 @@ copy_object (ibfd, obfd)
if (!bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
bfd_get_mach (ibfd)))
{
fprintf (stderr, "Output file cannot represent architecture %s\n",
fprintf (stderr,
"Warning: Output file cannot represent architecture %s\n",
bfd_printable_arch_mach (bfd_get_arch (ibfd),
bfd_get_mach (ibfd)));
}
@ -693,8 +790,14 @@ copy_object (ibfd, obfd)
|| strip_symbols == strip_unneeded
|| discard_locals != locals_undef
|| strip_specific_list != NULL
|| keep_specific_list != NULL
|| privatize_specific_list != NULL
|| weaken_specific_list != NULL
|| sections_removed
|| convert_debugging)
|| convert_debugging
|| change_leading_char
|| remove_leading_char
|| weaken)
{
/* Mark symbols used in output relocations so that they
are kept, even if they are local labels or static symbols.
@ -707,8 +810,8 @@ copy_object (ibfd, obfd)
bfd_map_over_sections (ibfd,
mark_symbols_used_in_relocations,
(PTR)isympp);
osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
symcount = filter_symbols (ibfd, osympp, isympp, symcount);
osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *));
symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
}
if (convert_debugging && dhandle != NULL)
@ -796,21 +899,6 @@ copy_object (ibfd, obfd)
}
}
static char *
cat (a, b, c)
char *a;
char *b;
char *c;
{
size_t size = strlen (a) + strlen (b) + strlen (c);
char *r = xmalloc (size + 1);
strcpy (r, a);
strcat (r, b);
strcat (r, c);
return r;
}
/* Read each archive element in turn from IBFD, copy the
contents to temp file, and keep the temp file handle. */
@ -818,7 +906,7 @@ static void
copy_archive (ibfd, obfd, output_target)
bfd *ibfd;
bfd *obfd;
char *output_target;
const char *output_target;
{
struct name_list
{
@ -844,7 +932,8 @@ copy_archive (ibfd, obfd, output_target)
while (this_element != (bfd *) NULL)
{
/* Create an output file for this member. */
char *output_name = cat (dir, "/", bfd_get_filename(this_element));
char *output_name = concat (dir, "/", bfd_get_filename(this_element),
(char *) NULL);
bfd *output_bfd = bfd_openw (output_name, output_target);
bfd *last_element;
@ -908,10 +997,10 @@ copy_archive (ibfd, obfd, output_target)
static void
copy_file (input_filename, output_filename, input_target, output_target)
char *input_filename;
char *output_filename;
char *input_target;
char *output_target;
const char *input_filename;
const char *output_filename;
const char *input_target;
const char *output_target;
{
bfd *ibfd;
char **matching;
@ -1303,6 +1392,57 @@ write_debugging_info (obfd, dhandle, symcountp, symppp)
if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
return write_ieee_debugging_info (obfd, dhandle);
if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
|| bfd_get_flavour (obfd) == bfd_target_elf_flavour)
{
bfd_byte *syms, *strings;
bfd_size_type symsize, stringsize;
asection *stabsec, *stabstrsec;
if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms,
&symsize, &strings,
&stringsize))
return false;
stabsec = bfd_make_section (obfd, ".stab");
stabstrsec = bfd_make_section (obfd, ".stabstr");
if (stabsec == NULL
|| stabstrsec == NULL
|| ! bfd_set_section_size (obfd, stabsec, symsize)
|| ! bfd_set_section_size (obfd, stabstrsec, stringsize)
|| ! bfd_set_section_alignment (obfd, stabsec, 2)
|| ! bfd_set_section_alignment (obfd, stabstrsec, 0)
|| ! bfd_set_section_flags (obfd, stabsec,
(SEC_HAS_CONTENTS
| SEC_READONLY
| SEC_DEBUGGING))
|| ! bfd_set_section_flags (obfd, stabstrsec,
(SEC_HAS_CONTENTS
| SEC_READONLY
| SEC_DEBUGGING)))
{
fprintf (stderr, "%s: can't create debugging section: %s\n",
bfd_get_filename (obfd), bfd_errmsg (bfd_get_error ()));
return false;
}
/* We can get away with setting the section contents now because
the next thing the caller is going to do is copy over the
real sections. We may someday have to split the contents
setting out of this function. */
if (! bfd_set_section_contents (obfd, stabsec, syms, (file_ptr) 0,
symsize)
|| ! bfd_set_section_contents (obfd, stabstrsec, strings,
(file_ptr) 0, stringsize))
{
fprintf (stderr, "%s: can't set debugging section contents: %s\n",
bfd_get_filename (obfd), bfd_errmsg (bfd_get_error ()));
return false;
}
return true;
}
fprintf (stderr,
"%s: don't know how to write debugging information for %s\n",
bfd_get_filename (obfd), bfd_get_target (obfd));
@ -1317,7 +1457,8 @@ write_debugging_info (obfd, dhandle, symcountp, symppp)
static int
simple_copy (from, to)
char *from, *to;
const char *from;
const char *to;
{
int fromfd, tofd, nread;
int saved;
@ -1371,7 +1512,8 @@ simple_copy (from, to)
static int
smart_rename (from, to)
char *from, *to;
const char *from;
const char *to;
{
struct stat s;
int ret = 0;
@ -1386,9 +1528,20 @@ smart_rename (from, to)
ret = rename (from, to);
if (ret == 0)
{
/* Try to preserve the permission bits and ownership of TO. */
chmod (to, s.st_mode & 07777);
chown (to, s.st_uid, s.st_gid);
/* Try to preserve the permission bits and ownership of TO.
First get the mode right except for the setuid bit. Then
change the ownership. Then fix the setuid bit. We do
the chmod before the chown because if the chown succeeds,
and we are a normal user, we won't be able to do the
chmod afterward. We don't bother to fix the setuid bit
first because that might introduce a fleeting security
problem, and because the chown will clear the setuid bit
anyhow. We only fix the setuid bit if the chown
succeeds, because we don't want to introduce an
unexpected setuid file owned by the user running objcopy. */
chmod (to, s.st_mode & 0777);
if (chown (to, s.st_uid, s.st_gid) >= 0)
chmod (to, s.st_mode & 07777);
}
else
{
@ -1415,6 +1568,49 @@ smart_rename (from, to)
return ret;
}
/* Set the times of the file DESTINATION to be the same as those in
STATBUF. */
static void
set_times (destination, statbuf)
const char *destination;
const struct stat *statbuf;
{
int result;
{
#ifdef HAVE_GOOD_UTIME_H
struct utimbuf tb;
tb.actime = statbuf->st_atime;
tb.modtime = statbuf->st_mtime;
result = utime (destination, &tb);
#else /* ! HAVE_GOOD_UTIME_H */
#ifndef HAVE_UTIMES
long tb[2];
tb[0] = statbuf->st_atime;
tb[1] = statbuf->st_mtime;
result = utime (destination, tb);
#else /* HAVE_UTIMES */
struct timeval tv[2];
tv[0].tv_sec = statbuf->st_atime;
tv[0].tv_usec = 0;
tv[1].tv_sec = statbuf->st_mtime;
tv[1].tv_usec = 0;
result = utimes (destination, tv);
#endif /* HAVE_UTIMES */
#endif /* ! HAVE_GOOD_UTIME_H */
}
if (result != 0)
{
fprintf (stderr, "%s: ", destination);
perror ("can not set time");
}
}
static int
strip_main (argc, argv)
int argc;
@ -1422,10 +1618,12 @@ strip_main (argc, argv)
{
char *input_target = NULL, *output_target = NULL;
boolean show_version = false;
boolean preserve_dates = false;
int c, i;
struct section_list *p;
char *output_file = NULL;
while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:sSgxXVv",
while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpgxXVv",
strip_options, (int *) 0)) != EOF)
{
switch (c)
@ -1455,23 +1653,16 @@ strip_main (argc, argv)
strip_symbols = strip_unneeded;
break;
case 'K':
if (! keep_symbols && strip_specific_list != NULL)
{
fprintf (stderr, "%s: Can not specify both -K and -N\n",
program_name);
strip_usage (stderr, 1);
}
keep_symbols = true;
add_strip_symbol (optarg);
add_specific_symbol (optarg, &keep_specific_list);
break;
case 'N':
if (keep_symbols)
{
fprintf (stderr, "%s: Can not specify both -K and -N\n",
program_name);
strip_usage (stderr, 1);
}
add_strip_symbol (optarg);
add_specific_symbol (optarg, &strip_specific_list);
break;
case 'o':
output_file = optarg;
break;
case 'p':
preserve_dates = true;
break;
case 'x':
discard_locals = locals_all;
@ -1495,10 +1686,7 @@ strip_main (argc, argv)
}
if (show_version)
{
printf ("GNU %s version %s\n", program_name, program_version);
exit (0);
}
print_version ("strip");
/* Default is to strip all symbols. */
if (strip_symbols == strip_undef
@ -1510,24 +1698,45 @@ strip_main (argc, argv)
output_target = input_target;
i = optind;
if (i == argc)
if (i == argc
|| (output_file != NULL && (i + 1) < argc))
strip_usage (stderr, 1);
for (; i < argc; i++)
{
int hold_status = status;
struct stat statbuf;
char *tmpname;
char *tmpname = make_tempname (argv[i]);
if (preserve_dates)
{
if (stat (argv[i], &statbuf) < 0)
{
fprintf (stderr, "%s: ", argv[i]);
perror ("cannot stat");
continue;
}
}
if (output_file != NULL)
tmpname = output_file;
else
tmpname = make_tempname (argv[i]);
status = 0;
copy_file (argv[i], tmpname, input_target, output_target);
if (status == 0)
{
smart_rename (tmpname, argv[i]);
if (preserve_dates)
set_times (tmpname, &statbuf);
if (output_file == NULL)
smart_rename (tmpname, argv[i]);
status = hold_status;
}
else
unlink (tmpname);
free (tmpname);
if (output_file == NULL)
free (tmpname);
}
return 0;
@ -1542,10 +1751,12 @@ copy_main (argc, argv)
char *input_target = NULL, *output_target = NULL;
boolean show_version = false;
boolean adjust_warn = true;
boolean preserve_dates = false;
int c;
struct section_list *p;
struct stat statbuf;
while ((c = getopt_long (argc, argv, "b:i:I:K:N:s:O:d:F:R:SgxXVv",
while ((c = getopt_long (argc, argv, "b:i:I:K:N:s:O:d:F:P:R:SpgxXVvW:",
copy_options, (int *) 0)) != EOF)
{
switch (c)
@ -1594,23 +1805,19 @@ copy_main (argc, argv)
strip_symbols = strip_unneeded;
break;
case 'K':
if (! keep_symbols && strip_specific_list != NULL)
{
fprintf (stderr, "%s: Can not specify both -K and -N\n",
program_name);
strip_usage (stderr, 1);
}
keep_symbols = true;
add_strip_symbol (optarg);
add_specific_symbol (optarg, &keep_specific_list);
break;
case 'N':
if (keep_symbols)
{
fprintf (stderr, "%s: Can not specify both -K and -N\n",
program_name);
strip_usage (stderr, 1);
}
add_strip_symbol (optarg);
add_specific_symbol (optarg, &strip_specific_list);
break;
case 'P':
add_specific_symbol (optarg, &privatize_specific_list);
break;
case 'W':
add_specific_symbol (optarg, &weaken_specific_list);
break;
case 'p':
preserve_dates = true;
break;
case 'x':
discard_locals = locals_all;
@ -1624,6 +1831,9 @@ copy_main (argc, argv)
case 'V':
show_version = true;
break;
case OPTION_WEAKEN:
weaken = true;
break;
case OPTION_ADD_SECTION:
{
const char *s;
@ -1734,6 +1944,9 @@ copy_main (argc, argv)
case OPTION_ADJUST_WARNINGS:
adjust_warn = true;
break;
case OPTION_CHANGE_LEADING_CHAR:
change_leading_char = true;
break;
case OPTION_DEBUGGING:
convert_debugging = true;
break;
@ -1760,6 +1973,9 @@ copy_main (argc, argv)
pad_to = parse_vma (optarg, "--pad-to");
pad_to_set = true;
break;
case OPTION_REMOVE_LEADING_CHAR:
remove_leading_char = true;
break;
case OPTION_SET_SECTION_FLAGS:
{
const char *s;
@ -1799,10 +2015,7 @@ copy_main (argc, argv)
}
if (show_version)
{
printf ("GNU %s version %s\n", program_name, program_version);
exit (0);
}
print_version ("objcopy");
if (copy_byte >= interleave)
{
@ -1825,21 +2038,38 @@ copy_main (argc, argv)
if (output_target == (char *) NULL)
output_target = input_target;
if (preserve_dates)
{
if (stat (input_filename, &statbuf) < 0)
{
fprintf (stderr, "%s: ", input_filename);
perror ("cannot stat");
exit (1);
}
}
/* If there is no destination file then create a temp and rename
the result into the input. */
if (output_filename == (char *) NULL)
{
char *tmpname = make_tempname (input_filename);
copy_file (input_filename, tmpname, input_target, output_target);
if (status == 0)
smart_rename (tmpname, input_filename);
{
if (preserve_dates)
set_times (tmpname, &statbuf);
smart_rename (tmpname, input_filename);
}
else
unlink (tmpname);
}
else
{
copy_file (input_filename, output_filename, input_target, output_target);
if (status == 0 && preserve_dates)
set_times (output_filename, &statbuf);
}
if (adjust_warn)
@ -1874,6 +2104,7 @@ main (argc, argv)
discard_locals = locals_undef;
bfd_init ();
set_default_bfd_target ();
if (is_strip < 0)
{