Initial revision

This commit is contained in:
David Henkel-Wallace 1991-03-21 21:29:06 +00:00
parent 6fd9467324
commit 2fa0b342a5
32 changed files with 13012 additions and 0 deletions

850
binutils/ar.c Normal file
View File

@ -0,0 +1,850 @@
/* ar.c - Archive modify and extract. */
/*
Bugs: should use getopt the way tar does (complete w/optional -) and
should have long options too. GNU ar used to check file against filesystem
in quick_update and replace operations (would check mtime). Doesn't warn
when name truncated. No way to specify pos_end. Error messages should be
more consistant.
*/
#include "sysdep.h"
#include "bfd.h"
#include "ar.h"
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#define BUFSIZE 8192
/* Not great to have these here. Should they be exported or not? */
PROTO(size_t, bfd_read, (void *ptr, size_t size, size_t nitems, bfd * abfd));
PROTO(size_t, bfd_write, (void *ptr, size_t size, size_t nitems, bfd * abfd));
/* PROTO (void, open_inarch, (char *archive_filename)); */
#ifdef __STDC__
static void open_inarch(char *archive_filename);
#else
static void open_inarch();
#endif /* __STDC__ */
PROTO(void, map_over_members, (void (*function) (), char **files, int count));
PROTO(void, print_contents, (bfd * member));
PROTO(void, extract_file, (bfd * abfd));
PROTO(void, delete_members, (char **files_to_delete));
PROTO(void, do_quick_append, (char *archive_filename, char **files_to_append));
PROTO(void, move_members, (char **files_to_move));
PROTO(void, replace_members, (char **files_to_replace));
PROTO(void, print_descr, (bfd * abfd));
PROTO(void, ranlib_only, (char *archname));
/** Globals and flags */
char *program_name = NULL;
bfd bogus_archive;
bfd *inarch; /* The input arch we're manipulating */
/* Nonzero means don't warn about creating the archive file if necessary. */
int silent_create = 0;
/* Nonzero means describe each action performed. */
int verbose = 0;
/* Nonzero means preserve dates of members when extracting them. */
int preserve_dates = 0;
/*
Nonzero means don't replace existing members whose dates are more recent
than the corresponding files.
*/
int newer_only = 0;
/* write a __.SYMDEF member into the modified archive. */
boolean write_armap = false;
/*
Nonzero means don't update __.SYMDEF unless command line explicitly
requested it
*/
int ignore_symdef = 0;
/*
Nonzero means it's the name of an existing member; position new or moved
files with respect to this one.
*/
char *posname = NULL;
/*
Sez how to use `posname': pos_before means position before that member.
pos_after means position after that member. pos_end means always at end.
pos_default means default appropriately. For the latter two, `posname'
should also be zero.
*/
enum pos {
pos_default, pos_before, pos_after, pos_end
} postype = pos_default;
/*
The option parsing should be in its own function. It will be when I have
getopt working.
*/
int
main(argc, argv)
int argc;
char **argv;
{
char *arg_ptr;
char c;
enum {
none = 0, delete, replace, print_table,
print_files, extract, move, quick_append
} operation = none;
int arg_index;
char **files;
char *inarch_filename;
char *temp;
program_name = argv[0];
temp = strrchr(program_name, '/');
if (temp == (char *) NULL)
temp = program_name; /* shouldn't happen, but... */
else
++temp;
if (!strcmp(temp, "ranlib")) {
if (argc < 2)
fatal("Too few command arguments.");
ranlib_only(argv[1]);
}
if (argc < 3)
fatal("Too few command arguments.");
arg_ptr = argv[1];
if (*arg_ptr == '-')
++arg_ptr; /* compatibility */
while (c = *arg_ptr++) {
switch (c) {
case 'd':
case 'm':
case 'p':
case 'q':
case 'r':
case 't':
case 'x':
if (operation != none)
fatal("two different operation switches specified");
switch (c) {
case 'd':
operation = delete;
break;
case 'm':
operation = move;
break;
case 'p':
operation = print_files;
break;
case 'q':
operation = quick_append;
break;
case 'r':
operation = replace;
break;
case 't':
operation = print_table;
break;
case 'x':
operation = extract;
break;
}
case 'l':
break;
case 'c':
silent_create = 1;
break;
case 'o':
preserve_dates = 1;
break;
case 's':
write_armap = true;
break;
case 'u':
newer_only = 1;
break;
case 'v':
verbose = 1;
break;
case 'a':
postype = pos_after;
break;
case 'b':
postype = pos_before;
break;
case 'i':
postype = pos_before;
break;
default:
fatal("invalid option %c", c);
}
}
if (operation == none && write_armap)
ranlib_only(argv[2]);
if (operation == none)
fatal("no operation specified");
if (newer_only && operation != replace)
fatal("'u' only meaningful with 'r' option.");
arg_index = 2;
if (postype != pos_default)
posname = argv[arg_index++];
inarch_filename = argv[arg_index++];
if (arg_index < argc) {
files = argv + arg_index;
while (arg_index < argc)
if (!strcmp(argv[arg_index++], "__.SYMDEF")) {
ignore_symdef = 1;
break;
}
}
else
files = NULL;
if (operation == quick_append) {
if (files != NULL)
do_quick_append(inarch_filename, files);
exit(0);
}
open_inarch(inarch_filename);
/*
If we have no archive, and we've been asked to replace then create one
*/
if (operation == replace &&
inarch == &bogus_archive) {
silent_create = 1;
do_quick_append(inarch_filename, 0);
open_inarch(inarch_filename);
}
switch (operation) {
case print_table:
map_over_members(print_descr, files, argc - 3);
break;
case print_files:
map_over_members(print_contents, files, argc - 3);
break;
case extract:
map_over_members(extract_file, files, argc - 3);
break;
case delete:
if (files != NULL)
delete_members(files);
break;
case move:
if (files != NULL)
move_members(files);
break;
case replace:
if (files != NULL || write_armap)
replace_members(files);
break;
/* Shouldn't happen! */
default:
fprintf(stderr, "Sorry; this option not implemented.\n");
}
return (0);
} /* main() */
static
char *normalize(file)
char *file;
{
char * filename = strrchr(file, '/');
if (filename != (char *)NULL) {
filename ++;
}
else {
filename = file;
}
return filename;
}
static void
open_inarch(archive_filename)
char *archive_filename;
{
bfd **last_one;
bfd *next_one;
struct stat sbuf;
bfd_error = no_error;
if (stat(archive_filename, &sbuf) != 0) {
if (errno != ENOENT)
bfd_fatal(archive_filename);
if (!silent_create)
fprintf(stderr,
"%s: creating %s\n", program_name, archive_filename);
inarch = &bogus_archive;
inarch->filename = archive_filename;
inarch->has_armap = true;
}
else {
inarch = bfd_openr(archive_filename, NULL);
if (inarch == NULL) {
bloser:
bfd_perror(archive_filename);
exit(1);
}
if (bfd_check_format(inarch, bfd_archive) != true)
fatal("File %s is not an archive.", archive_filename);
last_one = &(inarch->next);
/* Read all the contents right away, regardless. */
for (next_one = bfd_openr_next_archived_file(inarch, NULL);
next_one;
next_one = bfd_openr_next_archived_file(inarch, next_one)) {
*last_one = next_one;
last_one = &next_one->next;
}
*last_one = (bfd *) NULL;
if (bfd_error != no_more_archived_files)
goto bloser;
}
}
/*
If count is 0, then function is called once on each entry. if nonzero,
count is the length of the files chain; function is called on each entry
whose name matches one in files
*/
void
map_over_members(function, files, count)
void (*function) ();
char **files;
int count;
{
bfd *head;
if (count == 0) {
for (head = inarch->next; head; head = head->next)
function(head);
return;
}
/*
This may appear to be a baroque way of accomplishing what we want.
however we have to iterate over the filenames in order to notice where
a filename is requested but does not exist in the archive. Ditto
mapping over each file each time -- we want to hack multiple
references.
*/
for (; count > 0; files++, count--) {
boolean found = false;
for (head = inarch->next; head; head = head->next)
if ((head->filename != NULL) &&
(!strcmp(*files, head->filename))) {
found = true;
function(head);
}
if (!found)
fprintf(stderr, "No entry %s in archive.\n", *files);
}
}
/* Things which are interesting to map over all or some of the files: */
void
print_descr(abfd)
bfd *abfd;
{
print_arelt_descr(abfd, verbose);
}
void
print_contents(abfd)
bfd *abfd;
{
int ncopied = 0;
struct stat buf;
long size;
if (bfd_stat_arch_elt(abfd, &buf) != 0)
fatal("Internal stat error on %s", abfd->filename);
if (verbose)
printf("\n<member %s>\n\n", abfd->filename);
bfd_seek(abfd, 0, SEEK_SET);
size = buf.st_size;
while (ncopied < size) {
char cbuf[BUFSIZE];
int nread;
int tocopy = size - ncopied;
if (tocopy > BUFSIZE)
tocopy = BUFSIZE;
nread = bfd_read(cbuf, 1, tocopy, abfd); /* oops -- broke
abstraction! */
if (nread != tocopy)
fatal("file %s not a valid archive", abfd->my_archive->filename);
fwrite(cbuf, 1, nread, stdout);
ncopied += tocopy;
}
}
/*
Extract a member of the archive into its own file.
We defer opening the new file until after we have read a BUFSIZ chunk of the
old one, since we know we have just read the archive header for the old
one. Since most members are shorter than BUFSIZ, this means we will read
the old header, read the old data, write a new inode for the new file, and
write the new data, and be done. This 'optimization' is what comes from
sitting next to a bare disk and hearing it every time it seeks. -- Gnu
Gilmore
*/
void
extract_file(abfd)
bfd *abfd;
{
FILE *ostream;
char cbuf[BUFSIZE];
int nread,
tocopy;
int ncopied = 0;
long size;
struct stat buf;
if (bfd_stat_arch_elt(abfd, &buf) != 0)
fatal("Internal stat error on %s", abfd->filename);
size = buf.st_size;
if (verbose)
printf("x - %s\n", abfd->filename);
bfd_seek(abfd, 0, SEEK_SET);
ostream = 0;
while (ncopied < size) {
tocopy = size - ncopied;
if (tocopy > BUFSIZE)
tocopy = BUFSIZE;
nread = bfd_read(cbuf, 1, tocopy, abfd);
if (nread != tocopy)
fatal("file %s not a valid archive", abfd->my_archive->filename);
/* See comment above; this saves disk arm motion */
if (!ostream) {
/* Seems like an abstraction violation, eh? Well it's OK! */
ostream = fopen(abfd->filename, "w");
if (!ostream) {
perror(abfd->filename);
exit(1);
}
}
/* no need to byte-swap; the two formats are presumably compatible(!) */
fwrite(cbuf, 1, nread, ostream);
ncopied += tocopy;
}
fclose(ostream);
chmod(abfd->filename, buf.st_mode);
if (preserve_dates) {
#ifdef USG
long tb[2];
tb[0] = buf.st_mtime;
tb[1] = buf.st_mtime;
utime(abfd->filename, tb); /* FIXME check result */
#else
struct timeval tv[2];
tv[0].tv_sec = buf.st_mtime;
tv[0].tv_usec = 0;
tv[1].tv_sec = buf.st_mtime;
tv[1].tv_usec = 0;
utimes(abfd->filename, tv); /* FIXME check result */
#endif
}
}
/* Just do it quickly; don't worry about dups, armap, or anything like that */
/* This is ugly! XXX */
PROTO(struct ar_hdr *, bfd_special_undocumented_glue, (char *filename));
void
do_quick_append(archive_filename, files_to_append)
char *archive_filename;
char **files_to_append;
{
FILE *ofile,
*ifile;
char buf[BUFSIZE];
long tocopy,
thistime;
bfd *temp;
struct stat sbuf;
boolean newfile = false;
bfd_error = no_error;
if (stat(archive_filename, &sbuf) != 0) {
if (errno != ENOENT)
bfd_fatal(archive_filename);
newfile = true;
}
ofile = fopen(archive_filename, "a+");
if (ofile == NULL) {
perror(program_name);
exit(1);
}
/* bletch */
temp = bfd_openr(archive_filename, NULL);
if (temp == NULL) {
bfd_perror(archive_filename);
exit(1);
}
if (newfile == false) {
if (bfd_check_format(temp, bfd_archive) != true)
fatal("File %s is not an archive.", archive_filename);
}
else {
fwrite(ARMAG, 1, SARMAG, ofile);
if (!silent_create)
fprintf(stderr, "%s: creating %s\n", program_name, archive_filename);
}
/* assume it's an achive, go straight to the end, sans $200 */
fseek(ofile, 0, 2);
for (; files_to_append && *files_to_append; ++files_to_append) {
struct ar_hdr *hdr = bfd_special_undocumented_glue(*files_to_append);
if (hdr == NULL) {
bfd_perror(*files_to_append);
exit(1);
}
BFD_SEND(temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr));
ifile = fopen(*files_to_append, "r");
if (ifile == NULL)
bfd_perror(program_name);
if (stat(*files_to_append, &sbuf) != 0)
bfd_perror(*files_to_append);
tocopy = sbuf.st_size;
/* XXX should do error-checking! */
fwrite(hdr, 1, sizeof(struct ar_hdr), ofile);
while (tocopy > 0) {
thistime = tocopy;
if (thistime > BUFSIZE)
thistime = BUFSIZE;
fread(buf, 1, thistime, ifile);
fwrite(buf, 1, thistime, ofile);
tocopy -= thistime;
}
fclose(ifile);
if ((sbuf.st_size % 2) == 1)
putc('\n', ofile);
}
fclose(ofile);
bfd_close(temp);
}
void
write_archive()
{
bfd *obfd;
char *xmalloc();
int namelen = strlen(inarch->filename);
char *new_name = xmalloc(namelen + 6);
bfd *contents_head = inarch->next;
if (inarch == &bogus_archive) {
/* How can this be ? */
return;
}
else {
strcpy(new_name, inarch->filename);
strcpy(new_name + namelen, ".art");
obfd = bfd_openw(new_name, bfd_get_target(inarch));
if (obfd == NULL)
bfd_fatal(inarch->filename);
bfd_set_format(obfd, bfd_archive);
obfd->has_armap = write_armap;
if (bfd_set_archive_head(obfd, contents_head) != true)
bfd_fatal(inarch->filename);
if (!bfd_close(obfd))
bfd_fatal(inarch->filename);
if (rename(new_name, inarch->filename) != 0)
bfd_fatal(inarch->filename);
}
}
/*
returns a pointer to the pointer to the entry which should be rplacd'd
into when altering. default_pos should be how to interpret pos_default,
and should be a pos value.
*/
bfd **
get_pos_bfd(contents, default_pos)
bfd **contents;
enum pos default_pos;
{
bfd **after_bfd;
enum pos realpos = (postype == pos_default ? default_pos : postype);
switch (realpos) {
case pos_end:
after_bfd = contents;
while (*after_bfd) {
after_bfd = &((*after_bfd)->next);
}
break;
#if 0
case pos_after:
for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
if (!strcpy(after_bfd->filename, posname))
break;
break;
case pos_before:
for (after_bfd = contents; after_bfd; after_bfd = after_bfd->next)
if (after_bfd->next && (!strcpy(after_bfd->next->filename, posname)))
break;
#endif
}
return after_bfd;
}
void
delete_members(files_to_delete)
char **files_to_delete;
{
bfd **current_ptr_ptr;
boolean found;
boolean something_changed = false;
for (; *files_to_delete != NULL; ++files_to_delete) {
/*
In a.out systems, the armap is optional. It's also called
__.SYMDEF. So if the user asked to delete it, we should remember
that fact. The name is NULL in COFF archives, so using this as a
key is as good as anything I suppose
*/
if (!strcmp(*files_to_delete, "__.SYMDEF")) {
inarch->has_armap = false;
write_armap = false;
continue;
}
found = false;
current_ptr_ptr = &(inarch->next);
while (*current_ptr_ptr) {
if (strcmp(*files_to_delete, (*current_ptr_ptr)->filename) == 0) {
found = true;
something_changed = true;
if (verbose)
printf("d - %s\n",
*files_to_delete);
*current_ptr_ptr = ((*current_ptr_ptr)->next);
goto next_file;
}
else {
current_ptr_ptr = &((*current_ptr_ptr)->next);
}
}
if (verbose && found == false) {
printf("No member named `%s'\n", *files_to_delete);
}
next_file:;
}
if (something_changed == true) {
write_archive();
}
}
/* Reposition existing members within an archive */
void
move_members(files_to_move)
char **files_to_move;
{
bfd **after_bfd; /* New entries go after this one */
bfd **current_ptr_ptr; /* cdr pointer into contents */
for (; *files_to_move; ++files_to_move) {
current_ptr_ptr = &(inarch->next);
while (*current_ptr_ptr) {
bfd *current_ptr = *current_ptr_ptr;
if (strcmp(normalize(*files_to_move), current_ptr->filename) == 0) {
/*
Move this file to the end of the list - first cut from
where it is.
*/
*current_ptr_ptr = current_ptr->next;
/* Now glue to end */
after_bfd = get_pos_bfd(&inarch->next, pos_end);
*after_bfd = current_ptr;
current_ptr->next = (bfd *) NULL;
if (verbose)
printf("m - %s\n", *files_to_move);
goto next_file;
}
current_ptr_ptr = &((*current_ptr_ptr)->next);
}
fprintf(stderr, "No entry %s in archive %s!\n",
*files_to_move, inarch->filename);
exit(1);
next_file:;
}
write_archive();
}
/* Ought to default to replacing in place, but this is existing practice! */
void
replace_members(files_to_move)
char **files_to_move;
{
bfd **after_bfd; /* New entries go after this one */
bfd *current;
bfd **current_ptr;
bfd *temp;
/*
If the first item in the archive is an __.SYMDEF then remove it
*/
if (inarch->next &&
strcmp(inarch->next->filename, "__.SYMDEF") == 0) {
inarch->next = inarch->next->next;
}
while (files_to_move && *files_to_move) {
current_ptr = &inarch->next;
while (*current_ptr) {
current = *current_ptr;
if (!strcmp(normalize(*files_to_move), current->filename)) {
/* snip out this entry from the chain */
*current_ptr = current->next;
if (newer_only) {
struct stat fsbuf,
asbuf;
if (stat(*files_to_move, &fsbuf) != 0) {
if (errno != ENOENT)
bfd_fatal(*files_to_move);
goto next_file;
}
if (bfd_stat_arch_elt(current, &asbuf) != 0)
fatal("Internal stat error on %s", current->filename);
if (fsbuf.st_mtime <= asbuf.st_mtime)
goto next_file;
}
after_bfd = get_pos_bfd(&inarch->next, pos_end);
temp = *after_bfd;
*after_bfd = bfd_openr(*files_to_move, NULL);
if (*after_bfd == (bfd *) NULL) {
fprintf(stderr, "Can't open file %s\n", *files_to_move);
exit(1);
}
(*after_bfd)->next = temp;
if (verbose) {
printf("%c - %s\n", (postype == pos_after ? 'r' : 'a'),
*files_to_move);
}
goto next_file;
}
current_ptr = &(current->next);
}
/* It isn't in there, so add to end */
after_bfd = get_pos_bfd(&inarch->next, pos_end);
temp = *after_bfd;
*after_bfd = bfd_openr(*files_to_move, NULL);
if (*after_bfd == (bfd *) NULL) {
fprintf(stderr, "Can't open file %s\n", *files_to_move);
exit(1);
}
if (verbose) {
printf("c - %s\n", *files_to_move);
}
(*after_bfd)->next = temp;
next_file:;
files_to_move++;
}
write_archive();
}
void
ranlib_only(archname)
char *archname;
{
write_armap = true;
open_inarch(archname);
write_archive();
exit(0);
}

151
binutils/bucomm.c Normal file
View File

@ -0,0 +1,151 @@
/*** bucomm.c -- Bin Utils COMmon code.
We might put this in a library someday so it could be dynamically
loaded, but for now it's not necessary */
#include "sysdep.h"
#include "bfd.h"
#include <varargs.h>
char *target = NULL; /* default as late as possible */
/* Yes, this is what atexit is for, but that isn't guaranteed yet.
And yes, I know this isn't as good, but it does what is needed just fine */
void (*exit_handler) ();
/** Memory hackery */
PROTO (char *, malloc, (unsigned size));
PROTO (char *, realloc, (char *ptr, unsigned size));
/* Error reporting */
char *program_name;
void
bfd_fatal (string)
char *string;
{
char *errmsg = bfd_errmsg (bfd_error);
if (string)
fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
else
fprintf (stderr, "%s: %s\n", program_name, errmsg);
if (NULL != exit_handler) (*exit_handler) ();
exit (1);
}
#ifndef NO_STDARG
void
fatal (Format)
const char *Format;
{
va_list args;
va_start (args, Format);
vfprintf (stderr, Format, args);
va_end (args);
(void) putc ('\n', stderr);
if (NULL != exit_handler) (*exit_handler) ();
exit (1);
}
#else
#ifndef NO_VARARGS
void fatal (va_alist)
va_dcl
{
char *Format;
va_list args;
va_start (args);
Format = va_arg(args, char *);
vfprintf (stderr, Format, args);
va_end (args);
(void) putc ('\n', stderr);
if (NULL != exit_handler) (*exit_handler) ();
exit (1);
} /* fatal() */
#else
/*VARARGS1 */
fatal (Format, args)
char *Format;
{
as_where ();
_doprnt (Format, &args, stderr); /* not terribly portable, but... */
(void) putc ('\n', stderr);
if (NULL != exit_handler) (*exit_handler) ();
exit (1);
}
#endif /* not NO_VARARGS */
#endif /* not NO_STDARG */
/** Display the archive header for an element as if it were an ls -l listing */
/* Mode User\tGroup\tSize\tDate Name */
void
print_arelt_descr (abfd, verbose)
bfd *abfd;
boolean verbose;
{
struct stat buf;
char modebuf[11];
char timebuf[40];
long when;
long current_time = time ((long *) 0);
if (verbose) {
if (bfd_stat_arch_elt (abfd, &buf) == 0) { /* if not, huh? */
mode_string (buf.st_mode, modebuf);
modebuf[10] = '\0';
fputs (modebuf, stdout);
when = buf.st_mtime;
strcpy (timebuf, ctime (&when));
/* This code comes from gnu ls. */
if ((current_time - when > 6 * 30 * 24 * 60 * 60)
|| (current_time - when < 0)) {
/* The file is fairly old or in the future.
POSIX says the cutoff is 6 months old;
approximate this by 6*30 days.
Show the year instead of the time of day. */
strcpy (timebuf + 11, timebuf + 19);
}
timebuf[16] = 0;
printf (" %d\t%d\t%ld\t%s ", buf.st_uid, buf.st_gid, buf.st_size, timebuf);
}
}
puts (abfd->filename);
}
/* Like malloc but get fatal error if memory is exhausted. */
char *
xmalloc (size)
unsigned size;
{
register char *result = malloc (size);
if (result == NULL && size != NULL) fatal ("virtual memory exhausted");
return result;
}
/* Like realloc but get fatal error if memory is exhausted. */
char *
xrealloc (ptr, size)
char *ptr;
unsigned size;
{
register char *result = realloc (ptr, size);
if (result == 0 && size != 0) fatal ("virtual memory exhausted");
return result;
}

193
binutils/filemode.c Normal file
View File

@ -0,0 +1,193 @@
/* filemode.c -- make a string describing file modes
Copyright (C) 1985, 1990 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/types.h>
#include <sys/stat.h>
void mode_string ();
static char ftypelet ();
static void rwx ();
static void setst ();
/* filemodestring - fill in string STR with an ls-style ASCII
representation of the st_mode field of file stats block STATP.
10 characters are stored in STR; no terminating null is added.
The characters stored in STR are:
0 File type. 'd' for directory, 'c' for character
special, 'b' for block special, 'm' for multiplex,
'l' for symbolic link, 's' for socket, 'p' for fifo,
'-' for any other file type
1 'r' if the owner may read, '-' otherwise.
2 'w' if the owner may write, '-' otherwise.
3 'x' if the owner may execute, 's' if the file is
set-user-id, '-' otherwise.
'S' if the file is set-user-id, but the execute
bit isn't set.
4 'r' if group members may read, '-' otherwise.
5 'w' if group members may write, '-' otherwise.
6 'x' if group members may execute, 's' if the file is
set-group-id, '-' otherwise.
'S' if it is set-group-id but not executable.
7 'r' if any user may read, '-' otherwise.
8 'w' if any user may write, '-' otherwise.
9 'x' if any user may execute, 't' if the file is "sticky"
(will be retained in swap space after execution), '-'
otherwise.
'T' if the file is sticky but not executable. */
void
filemodestring (statp, str)
struct stat *statp;
char *str;
{
mode_string (statp->st_mode, str);
}
/* Like filemodestring, but only the relevant part of the `struct stat'
is given as an argument. */
void
mode_string (mode, str)
unsigned short mode;
char *str;
{
str[0] = ftypelet (mode);
rwx ((mode & 0700) << 0, &str[1]);
rwx ((mode & 0070) << 3, &str[4]);
rwx ((mode & 0007) << 6, &str[7]);
setst (mode, str);
}
/* Return a character indicating the type of file described by
file mode BITS:
'd' for directories
'b' for block special files
'c' for character special files
'm' for multiplexor files
'l' for symbolic links
's' for sockets
'p' for fifos
'-' for any other file type. */
static char
ftypelet (bits)
unsigned short bits;
{
switch (bits & S_IFMT)
{
default:
return '-';
case S_IFDIR:
return 'd';
#ifdef S_IFLNK
case S_IFLNK:
return 'l';
#endif
#ifdef S_IFCHR
case S_IFCHR:
return 'c';
#endif
#ifdef S_IFBLK
case S_IFBLK:
return 'b';
#endif
#ifdef S_IFMPC
case S_IFMPC:
case S_IFMPB:
return 'm';
#endif
#ifdef S_IFSOCK
case S_IFSOCK:
return 's';
#endif
#ifdef S_IFIFO
#if S_IFIFO != S_IFSOCK
case S_IFIFO:
return 'p';
#endif
#endif
#ifdef S_IFNWK /* HP-UX */
case S_IFNWK:
return 'n';
#endif
}
}
/* Look at read, write, and execute bits in BITS and set
flags in CHARS accordingly. */
static void
rwx (bits, chars)
unsigned short bits;
char *chars;
{
chars[0] = (bits & S_IREAD) ? 'r' : '-';
chars[1] = (bits & S_IWRITE) ? 'w' : '-';
chars[2] = (bits & S_IEXEC) ? 'x' : '-';
}
/* Set the 's' and 't' flags in file attributes string CHARS,
according to the file mode BITS. */
static void
setst (bits, chars)
unsigned short bits;
char *chars;
{
#ifdef S_ISUID
if (bits & S_ISUID)
{
if (chars[3] != 'x')
/* Set-uid, but not executable by owner. */
chars[3] = 'S';
else
chars[3] = 's';
}
#endif
#ifdef S_ISGID
if (bits & S_ISGID)
{
if (chars[6] != 'x')
/* Set-gid, but not executable by group. */
chars[6] = 'S';
else
chars[6] = 's';
}
#endif
#ifdef S_ISVTX
if (bits & S_ISVTX)
{
if (chars[9] != 'x')
/* Sticky, but not executable by others. */
chars[9] = 'T';
else
chars[9] = 't';
}
#endif
}

820
binutils/i960-pinsn.c Normal file
View File

@ -0,0 +1,820 @@
/* Disassemble i80960 instructions.
*/
/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Diddler.
BFD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
BFD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BFD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id$
$Log
*/
#include <stdio.h>
#include "sysdep.h"
#include "bfd.h"
extern char *xmalloc();
extern int fputs();
static char *reg_names[] = {
/* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7",
/* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
/* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
/* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp",
/* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3"
};
static FILE *stream; /* Output goes here */
static void print_addr();
static void ctrl();
static void cobr();
static void reg();
static int mem();
static void ea();
static void dstop();
static void regop();
static void invalid();
static int pinsn();
static void put_abs();
/* Print the i960 instruction at address 'memaddr' in debugged memory,
* on stream 's'. Returns length of the instruction, in bytes.
*/
int
print_insn_i960( memaddr, buffer, s )
bfd_vma memaddr;
uint8e_type *buffer;
FILE *s;
{
unsigned int word1, word2;
stream = s;
word1 =buffer [0] |( buffer[1]<< 8) | (buffer[2] << 16) | ( buffer[3] <<24);
word2 =buffer [4] |( buffer[5]<< 8) | (buffer[6] << 16) | ( buffer[7] <<24);
return pinsn( memaddr, word1, word2 );
}
#define IN_GDB
/*****************************************************************************
* All code below this point should be identical with that of
* the disassembler in gdmp960.
*****************************************************************************/
struct tabent {
char *name;
char numops;
};
static int
pinsn( memaddr, word1, word2 )
unsigned long memaddr;
unsigned long word1, word2;
{
int instr_len;
instr_len = 4;
put_abs( word1, word2 );
/* Divide instruction set into classes based on high 4 bits of opcode*/
switch ( (word1 >> 28) & 0xf ){
case 0x0:
case 0x1:
ctrl( memaddr, word1, word2 );
break;
case 0x2:
case 0x3:
cobr( memaddr, word1, word2 );
break;
case 0x5:
case 0x6:
case 0x7:
reg( word1 );
break;
case 0x8:
case 0x9:
case 0xa:
case 0xb:
case 0xc:
instr_len = mem( memaddr, word1, word2, 0 );
break;
default:
/* invalid instruction, print as data word */
invalid( word1 );
break;
}
return instr_len;
}
/****************************************/
/* CTRL format */
/****************************************/
static void
ctrl( memaddr, word1, word2 )
unsigned long memaddr;
unsigned long word1, word2;
{
int i;
static struct tabent ctrl_tab[] = {
NULL, 0, /* 0x00 */
NULL, 0, /* 0x01 */
NULL, 0, /* 0x02 */
NULL, 0, /* 0x03 */
NULL, 0, /* 0x04 */
NULL, 0, /* 0x05 */
NULL, 0, /* 0x06 */
NULL, 0, /* 0x07 */
"b", 1, /* 0x08 */
"call", 1, /* 0x09 */
"ret", 0, /* 0x0a */
"bal", 1, /* 0x0b */
NULL, 0, /* 0x0c */
NULL, 0, /* 0x0d */
NULL, 0, /* 0x0e */
NULL, 0, /* 0x0f */
"bno", 1, /* 0x10 */
"bg", 1, /* 0x11 */
"be", 1, /* 0x12 */
"bge", 1, /* 0x13 */
"bl", 1, /* 0x14 */
"bne", 1, /* 0x15 */
"ble", 1, /* 0x16 */
"bo", 1, /* 0x17 */
"faultno", 0, /* 0x18 */
"faultg", 0, /* 0x19 */
"faulte", 0, /* 0x1a */
"faultge", 0, /* 0x1b */
"faultl", 0, /* 0x1c */
"faultne", 0, /* 0x1d */
"faultle", 0, /* 0x1e */
"faulto", 0, /* 0x1f */
};
i = (word1 >> 24) & 0xff;
if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){
invalid( word1 );
return;
}
fputs( ctrl_tab[i].name, stream );
if ( word1 & 2 ){ /* Predicts branch not taken */
fputs( ".f", stream );
}
if ( ctrl_tab[i].numops == 1 ){
/* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */
word1 &= 0x00ffffff;
if ( word1 & 0x00800000 ){ /* Sign bit is set */
word1 |= (-1 & ~0xffffff); /* Sign extend */
}
putc( '\t', stream );
print_addr( word1 + memaddr );
}
}
/****************************************/
/* COBR format */
/****************************************/
static void
cobr( memaddr, word1, word2 )
unsigned long memaddr;
unsigned long word1, word2;
{
int src1;
int src2;
int i;
static struct tabent cobr_tab[] = {
"testno", 1, /* 0x20 */
"testg", 1, /* 0x21 */
"teste", 1, /* 0x22 */
"testge", 1, /* 0x23 */
"testl", 1, /* 0x24 */
"testne", 1, /* 0x25 */
"testle", 1, /* 0x26 */
"testo", 1, /* 0x27 */
NULL, 0, /* 0x28 */
NULL, 0, /* 0x29 */
NULL, 0, /* 0x2a */
NULL, 0, /* 0x2b */
NULL, 0, /* 0x2c */
NULL, 0, /* 0x2d */
NULL, 0, /* 0x2e */
NULL, 0, /* 0x2f */
"bbc", 3, /* 0x30 */
"cmpobg", 3, /* 0x31 */
"cmpobe", 3, /* 0x32 */
"cmpobge", 3, /* 0x33 */
"cmpobl", 3, /* 0x34 */
"cmpobne", 3, /* 0x35 */
"cmpoble", 3, /* 0x36 */
"bbs", 3, /* 0x37 */
"cmpibno", 3, /* 0x38 */
"cmpibg", 3, /* 0x39 */
"cmpibe", 3, /* 0x3a */
"cmpibge", 3, /* 0x3b */
"cmpibl", 3, /* 0x3c */
"cmpibne", 3, /* 0x3d */
"cmpible", 3, /* 0x3e */
"cmpibo", 3, /* 0x3f */
};
i = ((word1 >> 24) & 0xff) - 0x20;
if ( cobr_tab[i].name == NULL ){
invalid( word1 );
return;
}
fputs( cobr_tab[i].name, stream );
if ( word1 & 2 ){ /* Predicts branch not taken */
fputs( ".f", stream );
}
putc( '\t', stream );
src1 = (word1 >> 19) & 0x1f;
src2 = (word1 >> 14) & 0x1f;
if ( word1 & 0x02000 ){ /* M1 is 1 */
fprintf( stream, "%d", src1 );
} else { /* M1 is 0 */
fputs( reg_names[src1], stream );
}
if ( cobr_tab[i].numops > 1 ){
if ( word1 & 1 ){ /* S2 is 1 */
fprintf( stream, ",sf%d,", src2 );
} else { /* S1 is 0 */
fprintf( stream, ",%s,", reg_names[src2] );
}
/* Extract displacement and convert to address
*/
word1 &= 0x00001ffc;
if ( word1 & 0x00001000 ){ /* Negative displacement */
word1 |= (-1 & ~0x1fff); /* Sign extend */
}
print_addr( memaddr + word1 );
}
}
/****************************************/
/* MEM format */
/****************************************/
static int /* returns instruction length: 4 or 8 */
mem( memaddr, word1, word2, noprint )
unsigned long memaddr;
unsigned long word1, word2;
int noprint; /* If TRUE, return instruction length, but
* don't output any text.
*/
{
int i, j;
int len;
int mode;
int offset;
char *reg1, *reg2, *reg3;
/* This lookup table is too sparse to make it worth typing in, but not
* so large as to make a sparse array necessary. We allocate the
* table at runtime, initialize all entries to empty, and copy the
* real ones in from an initialization table.
*
* NOTE: In this table, the meaning of 'numops' is:
* 1: single operand
* 2: 2 operands, load instruction
* -2: 2 operands, store instruction
*/
static struct tabent *mem_tab = NULL;
static struct { int opcode; char *name; char numops; } mem_init[] = {
#define MEM_MIN 0x80
0x80, "ldob", 2,
0x82, "stob", -2,
0x84, "bx", 1,
0x85, "balx", 2,
0x86, "callx", 1,
0x88, "ldos", 2,
0x8a, "stos", -2,
0x8c, "lda", 2,
0x90, "ld", 2,
0x92, "st", -2,
0x98, "ldl", 2,
0x9a, "stl", -2,
0xa0, "ldt", 2,
0xa2, "stt", -2,
0xb0, "ldq", 2,
0xb2, "stq", -2,
0xc0, "ldib", 2,
0xc2, "stib", -2,
0xc8, "ldis", 2,
0xca, "stis", -2,
#define MEM_MAX 0xca
#define MEM_SIZ ((MEM_MAX-MEM_MIN+1) * sizeof(struct tabent))
0, NULL, 0
};
if ( mem_tab == NULL ){
mem_tab = (struct tabent *) xmalloc( MEM_SIZ );
bzero( (void *) mem_tab, MEM_SIZ );
for ( i = 0; mem_init[i].opcode != 0; i++ ){
j = mem_init[i].opcode - MEM_MIN;
mem_tab[j].name = mem_init[i].name;
mem_tab[j].numops = mem_init[i].numops;
}
}
i = ((word1 >> 24) & 0xff) - MEM_MIN;
mode = (word1 >> 10) & 0xf;
if ( (mem_tab[i].name != NULL) /* Valid instruction */
&& ((mode == 5) || (mode >=12)) ){ /* With 32-bit displacement */
len = 8;
} else {
len = 4;
}
if ( noprint ){
return len;
}
if ( (mem_tab[i].name == NULL) || (mode == 6) ){
invalid( word1 );
return len;
}
fprintf( stream, "%s\t", mem_tab[i].name );
reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */
reg2 = reg_names[ (word1 >> 14) & 0x1f ];
reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */
offset = word1 & 0xfff; /* MEMA only */
switch ( mem_tab[i].numops ){
case 2: /* LOAD INSTRUCTION */
if ( mode & 4 ){ /* MEMB FORMAT */
ea( memaddr, mode, reg2, reg3, word1, word2 );
fprintf( stream, ",%s", reg1 );
} else { /* MEMA FORMAT */
fprintf( stream, "0x%x", (unsigned) offset );
if (mode & 8) {
fprintf( stream, "(%s)", reg2 );
}
fprintf( stream, ",%s", reg1 );
}
break;
case -2: /* STORE INSTRUCTION */
if ( mode & 4 ){ /* MEMB FORMAT */
fprintf( stream, "%s,", reg1 );
ea( memaddr, mode, reg2, reg3, word1, word2 );
} else { /* MEMA FORMAT */
fprintf( stream, "%s,0x%x", reg1, (unsigned) offset );
if (mode & 8) {
fprintf( stream, "(%s)", reg2 );
}
}
break;
case 1: /* BX/CALLX INSTRUCTION */
if ( mode & 4 ){ /* MEMB FORMAT */
ea( memaddr, mode, reg2, reg3, word1, word2 );
} else { /* MEMA FORMAT */
fprintf( stream, "0x%x", (unsigned) offset );
if (mode & 8) {
fprintf( stream, "(%s)", reg2 );
}
}
break;
}
return len;
}
/****************************************/
/* REG format */
/****************************************/
static void
reg( word1 )
unsigned long word1;
{
int i, j;
int opcode;
int fp;
int m1, m2, m3;
int s1, s2;
int src, src2, dst;
char *mnemp;
/* This lookup table is too sparse to make it worth typing in, but not
* so large as to make a sparse array necessary. We allocate the
* table at runtime, initialize all entries to empty, and copy the
* real ones in from an initialization table.
*
* NOTE: In this table, the meaning of 'numops' is:
* 1: single operand, which is NOT a destination.
* -1: single operand, which IS a destination.
* 2: 2 operands, the 2nd of which is NOT a destination.
* -2: 2 operands, the 2nd of which IS a destination.
* 3: 3 operands
*
* If an opcode mnemonic begins with "F", it is a floating-point
* opcode (the "F" is not printed).
*/
static struct tabent *reg_tab = NULL;
static struct { int opcode; char *name; char numops; } reg_init[] = {
#define REG_MIN 0x580
0x580, "notbit", 3,
0x581, "and", 3,
0x582, "andnot", 3,
0x583, "setbit", 3,
0x584, "notand", 3,
0x586, "xor", 3,
0x587, "or", 3,
0x588, "nor", 3,
0x589, "xnor", 3,
0x58a, "not", -2,
0x58b, "ornot", 3,
0x58c, "clrbit", 3,
0x58d, "notor", 3,
0x58e, "nand", 3,
0x58f, "alterbit", 3,
0x590, "addo", 3,
0x591, "addi", 3,
0x592, "subo", 3,
0x593, "subi", 3,
0x598, "shro", 3,
0x59a, "shrdi", 3,
0x59b, "shri", 3,
0x59c, "shlo", 3,
0x59d, "rotate", 3,
0x59e, "shli", 3,
0x5a0, "cmpo", 2,
0x5a1, "cmpi", 2,
0x5a2, "concmpo", 2,
0x5a3, "concmpi", 2,
0x5a4, "cmpinco", 3,
0x5a5, "cmpinci", 3,
0x5a6, "cmpdeco", 3,
0x5a7, "cmpdeci", 3,
0x5ac, "scanbyte", 2,
0x5ae, "chkbit", 2,
0x5b0, "addc", 3,
0x5b2, "subc", 3,
0x5cc, "mov", -2,
0x5d8, "eshro", 3,
0x5dc, "movl", -2,
0x5ec, "movt", -2,
0x5fc, "movq", -2,
0x600, "synmov", 2,
0x601, "synmovl", 2,
0x602, "synmovq", 2,
0x603, "cmpstr", 3,
0x604, "movqstr", 3,
0x605, "movstr", 3,
0x610, "atmod", 3,
0x612, "atadd", 3,
0x613, "inspacc", -2,
0x614, "ldphy", -2,
0x615, "synld", -2,
0x617, "fill", 3,
0x630, "sdma", 3,
0x631, "udma", 0,
0x640, "spanbit", -2,
0x641, "scanbit", -2,
0x642, "daddc", 3,
0x643, "dsubc", 3,
0x644, "dmovt", -2,
0x645, "modac", 3,
0x646, "condrec", -2,
0x650, "modify", 3,
0x651, "extract", 3,
0x654, "modtc", 3,
0x655, "modpc", 3,
0x656, "receive", -2,
0x659, "sysctl", 3,
0x660, "calls", 1,
0x662, "send", 3,
0x663, "sendserv", 1,
0x664, "resumprcs", 1,
0x665, "schedprcs", 1,
0x666, "saveprcs", 0,
0x668, "condwait", 1,
0x669, "wait", 1,
0x66a, "signal", 1,
0x66b, "mark", 0,
0x66c, "fmark", 0,
0x66d, "flushreg", 0,
0x66f, "syncf", 0,
0x670, "emul", 3,
0x671, "ediv", 3,
0x673, "ldtime", -1,
0x674, "Fcvtir", -2,
0x675, "Fcvtilr", -2,
0x676, "Fscalerl", 3,
0x677, "Fscaler", 3,
0x680, "Fatanr", 3,
0x681, "Flogepr", 3,
0x682, "Flogr", 3,
0x683, "Fremr", 3,
0x684, "Fcmpor", 2,
0x685, "Fcmpr", 2,
0x688, "Fsqrtr", -2,
0x689, "Fexpr", -2,
0x68a, "Flogbnr", -2,
0x68b, "Froundr", -2,
0x68c, "Fsinr", -2,
0x68d, "Fcosr", -2,
0x68e, "Ftanr", -2,
0x68f, "Fclassr", 1,
0x690, "Fatanrl", 3,
0x691, "Flogeprl", 3,
0x692, "Flogrl", 3,
0x693, "Fremrl", 3,
0x694, "Fcmporl", 2,
0x695, "Fcmprl", 2,
0x698, "Fsqrtrl", -2,
0x699, "Fexprl", -2,
0x69a, "Flogbnrl", -2,
0x69b, "Froundrl", -2,
0x69c, "Fsinrl", -2,
0x69d, "Fcosrl", -2,
0x69e, "Ftanrl", -2,
0x69f, "Fclassrl", 1,
0x6c0, "Fcvtri", -2,
0x6c1, "Fcvtril", -2,
0x6c2, "Fcvtzri", -2,
0x6c3, "Fcvtzril", -2,
0x6c9, "Fmovr", -2,
0x6d9, "Fmovrl", -2,
0x6e1, "Fmovre", -2,
0x6e2, "Fcpysre", 3,
0x6e3, "Fcpyrsre", 3,
0x701, "mulo", 3,
0x708, "remo", 3,
0x70b, "divo", 3,
0x741, "muli", 3,
0x748, "remi", 3,
0x749, "modi", 3,
0x74b, "divi", 3,
0x78b, "Fdivr", 3,
0x78c, "Fmulr", 3,
0x78d, "Fsubr", 3,
0x78f, "Faddr", 3,
0x79b, "Fdivrl", 3,
0x79c, "Fmulrl", 3,
0x79d, "Fsubrl", 3,
0x79f, "Faddrl", 3,
#define REG_MAX 0x79f
#define REG_SIZ ((REG_MAX-REG_MIN+1) * sizeof(struct tabent))
0, NULL, 0
};
if ( reg_tab == NULL ){
reg_tab = (struct tabent *) xmalloc( REG_SIZ );
bzero( (void *) reg_tab, REG_SIZ );
for ( i = 0; reg_init[i].opcode != 0; i++ ){
j = reg_init[i].opcode - REG_MIN;
reg_tab[j].name = reg_init[i].name;
reg_tab[j].numops = reg_init[i].numops;
}
}
opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
i = opcode - REG_MIN;
if ( (opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL) ){
invalid( word1 );
return;
}
mnemp = reg_tab[i].name;
if ( *mnemp == 'F' ){
fp = 1;
mnemp++;
} else {
fp = 0;
}
fputs( mnemp, stream );
s1 = (word1 >> 5) & 1;
s2 = (word1 >> 6) & 1;
m1 = (word1 >> 11) & 1;
m2 = (word1 >> 12) & 1;
m3 = (word1 >> 13) & 1;
src = word1 & 0x1f;
src2 = (word1 >> 14) & 0x1f;
dst = (word1 >> 19) & 0x1f;
if ( reg_tab[i].numops != 0 ){
putc( '\t', stream );
switch ( reg_tab[i].numops ){
case 1:
regop( m1, s1, src, fp );
break;
case -1:
dstop( m3, dst, fp );
break;
case 2:
regop( m1, s1, src, fp );
putc( ',', stream );
regop( m2, s2, src2, fp );
break;
case -2:
regop( m1, s1, src, fp );
putc( ',', stream );
dstop( m3, dst, fp );
break;
case 3:
regop( m1, s1, src, fp );
putc( ',', stream );
regop( m2, s2, src2, fp );
putc( ',', stream );
dstop( m3, dst, fp );
break;
}
}
}
/*
* Print out effective address for memb instructions.
*/
static void
ea( memaddr, mode, reg2, reg3, word1, word2 )
unsigned long memaddr;
int mode;
char *reg2, *reg3;
int word1;
unsigned int word2;
{
int scale;
static int scale_tab[] = { 1, 2, 4, 8, 16 };
scale = (word1 >> 7) & 0x07;
if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){
invalid( word1 );
return;
}
scale = scale_tab[scale];
switch (mode) {
case 4: /* (reg) */
fprintf( stream, "(%s)", reg2 );
break;
case 5: /* displ+8(ip) */
print_addr( word2+8+memaddr );
break;
case 7: /* (reg)[index*scale] */
if (scale == 1) {
fprintf( stream, "(%s)[%s]", reg2, reg3 );
} else {
fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale);
}
break;
case 12: /* displacement */
print_addr( word2 );
break;
case 13: /* displ(reg) */
print_addr( word2 );
fprintf( stream, "(%s)", reg2 );
break;
case 14: /* displ[index*scale] */
print_addr( word2 );
if (scale == 1) {
fprintf( stream, "[%s]", reg3 );
} else {
fprintf( stream, "[%s*%d]", reg3, scale );
}
break;
case 15: /* displ(reg)[index*scale] */
print_addr( word2 );
if (scale == 1) {
fprintf( stream, "(%s)[%s]", reg2, reg3 );
} else {
fprintf( stream, "(%s)[%s*%d]",reg2,reg3,scale );
}
break;
default:
invalid( word1 );
return;
}
}
/************************************************/
/* Register Instruction Operand */
/************************************************/
static void
regop( mode, spec, reg, fp )
int mode, spec, reg, fp;
{
if ( fp ){ /* FLOATING POINT INSTRUCTION */
if ( mode == 1 ){ /* FP operand */
switch ( reg ){
case 0: fputs( "fp0", stream ); break;
case 1: fputs( "fp1", stream ); break;
case 2: fputs( "fp2", stream ); break;
case 3: fputs( "fp3", stream ); break;
case 16: fputs( "0f0.0", stream ); break;
case 22: fputs( "0f1.0", stream ); break;
default: putc( '?', stream ); break;
}
} else { /* Non-FP register */
fputs( reg_names[reg], stream );
}
} else { /* NOT FLOATING POINT */
if ( mode == 1 ){ /* Literal */
fprintf( stream, "%d", reg );
} else { /* Register */
if ( spec == 0 ){
fputs( reg_names[reg], stream );
} else {
fprintf( stream, "sf%d", reg );
}
}
}
}
/************************************************/
/* Register Instruction Destination Operand */
/************************************************/
static void
dstop( mode, reg, fp )
int mode, reg, fp;
{
/* 'dst' operand can't be a literal. On non-FP instructions, register
* mode is assumed and "m3" acts as if were "s3"; on FP-instructions,
* sf registers are not allowed so m3 acts normally.
*/
if ( fp ){
regop( mode, 0, reg, fp );
} else {
regop( 0, mode, reg, fp );
}
}
static void
invalid( word1 )
int word1;
{
fprintf( stream, ".word\t0x%08x", (unsigned) word1 );
}
static void
print_addr(a)
int a;
{
fprintf( stream, "0x%x", (unsigned) a );
}
static void
put_abs( word1, word2 )
unsigned long word1, word2;
{
#ifdef IN_GDB
return;
#else
int len;
switch ( (word1 >> 28) & 0xf ){
case 0x8:
case 0x9:
case 0xa:
case 0xb:
case 0xc:
/* MEM format instruction */
len = mem( 0, word1, word2, 1 );
break;
default:
len = 4;
break;
}
if ( len == 8 ){
fprintf( stream, "%08x %08x\t", word1, word2 );
} else {
fprintf( stream, "%08x \t", word1 );
}
;
#endif
}

806
binutils/m68k-pinsn.c Normal file
View File

@ -0,0 +1,806 @@
/* Print m68k instructions for objdump
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This file is part of the binutils.
The binutils are free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
The binutils are distributed in the hope that they will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the binutils; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id$
$Log$
Revision 1.1 1991/03/21 21:26:45 gumby
Initial revision
* Revision 1.1 1991/03/13 00:34:06 chrisb
* Initial revision
*
* Revision 1.4 1991/03/09 04:36:34 rich
* Modified Files:
* sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
* binutils.h
*
* Pulled sysdep.h out of bfd.h.
*
* Revision 1.3 1991/03/08 21:54:45 rich
* Modified Files:
* Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
* i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
* sparc-pinsn.c strip.c
*
* Verifying Portland tree with steve's last changes. Also, some partial
* porting.
*
* Revision 1.2 1991/03/08 07:46:24 sac
* Added -l option to disassembly - prints line numbers too.
*
* Revision 1.1 1991/02/22 16:48:02 sac
* Initial revision
*
*/
#include <stdio.h>
#include "sysdep.h"
#include "bfd.h"
#include "m68k-opcode.h"
extern int fputs();
extern void print_address();
/* 68k instructions are never longer than this many bytes. */
#define MAXLEN 22
/* Number of elements in the opcode table. */
#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
extern char *reg_names[];
char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
"fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
static unsigned char *print_insn_arg ();
static unsigned char *print_indexed ();
static void print_base ();
static int fetch_arg ();
#define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
#define NEXTWORD(p) \
(p += 2, ((((char *)p)[-2]) << 8) + p[-1])
#define NEXTLONG(p) \
(p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
#define NEXTSINGLE(p) \
(p += 4, *((float *)(p - 4)))
#define NEXTDOUBLE(p) \
(p += 8, *((double *)(p - 8)))
#define NEXTEXTEND(p) \
(p += 12, 0.0) /* Need a function to convert from extended to double
precision... */
#define NEXTPACKED(p) \
(p += 12, 0.0) /* Need a function to convert from packed to double
precision. Actually, it's easier to print a
packed number than a double anyway, so maybe
there should be a special case to handle this... */
/* Print the m68k instruction at address MEMADDR in debugged memory,
on STREAM. Returns length of the instruction, in bytes. */
int
print_insn_m68k(addr, buffer, stream)
bfd_vma addr;
unsigned char *buffer;
FILE *stream;
{
register unsigned int i;
register unsigned char *p;
register char *d;
register unsigned int bestmask;
int best;
bestmask = 0;
best = -1;
for (i = 0; i < NOPCODES; i++)
{
register unsigned int opcode = m68k_opcodes[i].opcode;
register unsigned int match = m68k_opcodes[i].match;
if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
&& ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
&& ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
&& ((0xff & buffer[3] & match) == (0xff & opcode)))
{
/* Don't use for printout the variants of divul and divsl
that have the same register number in two places.
The more general variants will match instead. */
for (d = m68k_opcodes[i].args; *d; d += 2)
if (d[1] == 'D')
break;
/* Don't use for printout the variants of most floating
point coprocessor instructions which use the same
register number in two places, as above. */
if (*d == 0)
for (d = m68k_opcodes[i].args; *d; d += 2)
if (d[1] == 't')
break;
if (*d == 0 && match > bestmask)
{
best = i;
bestmask = match;
}
}
}
/* Handle undefined instructions. */
if (best < 0)
{
fprintf (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]);
return 2;
}
fprintf (stream, "%s", m68k_opcodes[best].name);
/* Point at first word of argument data,
and at descriptor for first argument. */
p = buffer + 2;
/* Why do this this way? -MelloN */
for (d = m68k_opcodes[best].args; *d; d += 2)
{
if (d[0] == '#')
{
if (d[1] == 'l' && p - buffer < 6)
p = buffer + 6;
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
p = buffer + 4;
}
if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
p = buffer + 4;
if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
p = buffer + 6;
if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
p = buffer + 4;
}
d = m68k_opcodes[best].args;
if (*d)
fputs (" ", stream);
while (*d)
{
p = print_insn_arg (d, buffer, p, addr + p - buffer, stream);
d += 2;
if (*d && *(d - 2) != 'I' && *d != 'k')
fputs (",", stream);
}
return p - buffer;
}
static unsigned char *
print_insn_arg (d, buffer, p, addr, stream)
char *d;
unsigned char *buffer;
register unsigned char *p;
bfd_vma addr; /* PC for this arg to be relative to */
FILE *stream;
{
register int val;
register int place = d[1];
int regno;
register char *regname;
register unsigned char *p1;
register double flval;
int flt_p;
switch (*d)
{
case 'C':
fprintf (stream, "ccr");
break;
case 'S':
fprintf (stream, "sr");
break;
case 'U':
fprintf (stream, "usp");
break;
case 'J':
{
static struct { char *name; int value; } names[]
= {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
{"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
{"msp", 0x803}, {"isp", 0x804}};
val = fetch_arg (buffer, place, 12);
for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
if (names[regno].value == val)
{
fprintf (stream, names[regno].name);
break;
}
if (regno < 0)
fprintf (stream, "%d", val);
}
break;
case 'Q':
val = fetch_arg (buffer, place, 3);
if (val == 0) val = 8;
fprintf (stream, "#%d", val);
break;
case 'M':
val = fetch_arg (buffer, place, 8);
if (val & 0x80)
val = val - 0x100;
fprintf (stream, "#%d", val);
break;
case 'T':
val = fetch_arg (buffer, place, 4);
fprintf (stream, "#%d", val);
break;
case 'D':
fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
break;
case 'A':
fprintf (stream, "%s",
reg_names[fetch_arg (buffer, place, 3) + 010]);
break;
case 'R':
fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
break;
case 'F':
fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
break;
case 'O':
val = fetch_arg (buffer, place, 6);
if (val & 0x20)
fprintf (stream, "%s", reg_names [val & 7]);
else
fprintf (stream, "%d", val);
break;
case '+':
fprintf (stream, "%s@+",
reg_names[fetch_arg (buffer, place, 3) + 8]);
break;
case '-':
fprintf (stream, "%s@-",
reg_names[fetch_arg (buffer, place, 3) + 8]);
break;
case 'k':
if (place == 'k')
fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
else if (place == 'C')
{
val = fetch_arg (buffer, place, 7);
if ( val > 63 ) /* This is a signed constant. */
val -= 128;
fprintf (stream, "{#%d}", val);
}
else
fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
*d, place);
break;
case '#':
case '^':
p1 = buffer + (*d == '#' ? 2 : 4);
if (place == 's')
val = fetch_arg (buffer, place, 4);
else if (place == 'C')
val = fetch_arg (buffer, place, 7);
else if (place == '8')
val = fetch_arg (buffer, place, 3);
else if (place == '3')
val = fetch_arg (buffer, place, 8);
else if (place == 'b')
val = NEXTBYTE (p1);
else if (place == 'w')
val = NEXTWORD (p1);
else if (place == 'l')
val = NEXTLONG (p1);
else
fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
*d, place);
fprintf (stream, "#%d", val);
break;
case 'B':
if (place == 'b')
val = NEXTBYTE (p);
else if (place == 'w')
val = NEXTWORD (p);
else if (place == 'l')
val = NEXTLONG (p);
else if (place == 'g')
{
val = ((char *)buffer)[1];
if (val == 0)
val = NEXTWORD (p);
else if (val == -1)
val = NEXTLONG (p);
}
else if (place == 'c')
{
if (buffer[1] & 0x40) /* If bit six is one, long offset */
val = NEXTLONG (p);
else
val = NEXTWORD (p);
}
else
fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
*d, place);
print_address (addr + val, stream);
break;
case 'd':
val = NEXTWORD (p);
fprintf (stream, "%s@(%d)",
reg_names[fetch_arg (buffer, place, 3)], val);
break;
case 's':
fprintf (stream, "%s",
fpcr_names[fetch_arg (buffer, place, 3)]);
break;
case 'I':
val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
if (val != 1) /* Unusual coprocessor ID? */
fprintf (stream, "(cpid=%d) ", val);
if (place == 'i')
p += 2; /* Skip coprocessor extended operands */
break;
case '*':
case '~':
case '%':
case ';':
case '@':
case '!':
case '$':
case '?':
case '/':
case '&':
if (place == 'd')
{
val = fetch_arg (buffer, 'x', 6);
val = ((val & 7) << 3) + ((val >> 3) & 7);
}
else
val = fetch_arg (buffer, 's', 6);
/* Get register number assuming address register. */
regno = (val & 7) + 8;
regname = reg_names[regno];
switch (val >> 3)
{
case 0:
fprintf (stream, "%s", reg_names[val]);
break;
case 1:
fprintf (stream, "%s", regname);
break;
case 2:
fprintf (stream, "%s@", regname);
break;
case 3:
fprintf (stream, "%s@+", regname);
break;
case 4:
fprintf (stream, "%s@-", regname);
break;
case 5:
val = NEXTWORD (p);
fprintf (stream, "%s@(%d)", regname, val);
break;
case 6:
p = print_indexed (regno, p, addr, stream);
break;
case 7:
switch (val & 7)
{
case 0:
val = NEXTWORD (p);
fprintf (stream, "@#");
print_address (val, stream);
break;
case 1:
val = NEXTLONG (p);
fprintf (stream, "@#");
print_address (val, stream);
break;
case 2:
val = NEXTWORD (p);
print_address (addr + val, stream);
break;
case 3:
p = print_indexed (-1, p, addr, stream);
break;
case 4:
flt_p = 1; /* Assume it's a float... */
switch( place )
{
case 'b':
val = NEXTBYTE (p);
flt_p = 0;
break;
case 'w':
val = NEXTWORD (p);
flt_p = 0;
break;
case 'l':
val = NEXTLONG (p);
flt_p = 0;
break;
case 'f':
flval = NEXTSINGLE(p);
break;
case 'F':
flval = NEXTDOUBLE(p);
break;
case 'x':
flval = NEXTEXTEND(p);
break;
case 'p':
flval = NEXTPACKED(p);
break;
default:
fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
*d, place);
}
if ( flt_p ) /* Print a float? */
fprintf (stream, "#%g", flval);
else
fprintf (stream, "#%d", val);
break;
default:
fprintf (stream, "<invalid address mode 0%o>", (unsigned) val);
}
}
break;
case 'L':
case 'l':
if (place == 'w')
{
char doneany;
p1 = buffer + 2;
val = NEXTWORD (p1);
/* Move the pointer ahead if this point is farther ahead
than the last. */
p = p1 > p ? p1 : p;
if (val == 0)
{
fputs ("#0", stream);
break;
}
if (*d == 'l')
{
register int newval = 0;
for (regno = 0; regno < 16; ++regno)
if (val & (0x8000 >> regno))
newval |= 1 << regno;
val = newval;
}
val &= 0xffff;
doneany = 0;
for (regno = 0; regno < 16; ++regno)
if (val & (1 << regno))
{
int first_regno;
if (doneany)
fputs ("/", stream);
doneany = 1;
fprintf (stream, "%s", reg_names[regno]);
first_regno = regno;
while (val & (1 << (regno + 1)))
++regno;
if (regno > first_regno)
fprintf (stream, "-%s", reg_names[regno]);
}
}
else if (place == '3')
{
/* `fmovem' insn. */
char doneany;
val = fetch_arg (buffer, place, 8);
if (val == 0)
{
fputs ("#0", stream);
break;
}
if (*d == 'l')
{
register int newval = 0;
for (regno = 0; regno < 8; ++regno)
if (val & (0x80 >> regno))
newval |= 1 << regno;
val = newval;
}
val &= 0xff;
doneany = 0;
for (regno = 0; regno < 8; ++regno)
if (val & (1 << regno))
{
int first_regno;
if (doneany)
fputs ("/", stream);
doneany = 1;
fprintf (stream, "fp%d", regno);
first_regno = regno;
while (val & (1 << (regno + 1)))
++regno;
if (regno > first_regno)
fprintf (stream, "-fp%d", regno);
}
}
else
abort ();
break;
default:
fprintf(stderr, "Invalid arg format in opcode table: \"%c\".", *d);
}
return (unsigned char *) p;
}
/* Fetch BITS bits from a position in the instruction specified by CODE.
CODE is a "place to put an argument", or 'x' for a destination
that is a general address (mode and register).
BUFFER contains the instruction. */
static int
fetch_arg (buffer, code, bits)
unsigned char *buffer;
char code;
int bits;
{
register int val;
switch (code)
{
case 's':
val = buffer[1];
break;
case 'd': /* Destination, for register or quick. */
val = (buffer[0] << 8) + buffer[1];
val >>= 9;
break;
case 'x': /* Destination, for general arg */
val = (buffer[0] << 8) + buffer[1];
val >>= 6;
break;
case 'k':
val = (buffer[3] >> 4);
break;
case 'C':
val = buffer[3];
break;
case '1':
val = (buffer[2] << 8) + buffer[3];
val >>= 12;
break;
case '2':
val = (buffer[2] << 8) + buffer[3];
val >>= 6;
break;
case '3':
case 'j':
val = (buffer[2] << 8) + buffer[3];
break;
case '4':
val = (buffer[4] << 8) + buffer[5];
val >>= 12;
break;
case '5':
val = (buffer[4] << 8) + buffer[5];
val >>= 6;
break;
case '6':
val = (buffer[4] << 8) + buffer[5];
break;
case '7':
val = (buffer[2] << 8) + buffer[3];
val >>= 7;
break;
case '8':
val = (buffer[2] << 8) + buffer[3];
val >>= 10;
break;
default:
abort ();
}
switch (bits)
{
case 3:
return val & 7;
case 4:
return val & 017;
case 5:
return val & 037;
case 6:
return val & 077;
case 7:
return val & 0177;
case 8:
return val & 0377;
case 12:
return val & 07777;
default:
abort ();
return(0);
}
} /* fetch_arg() */
/* Print an indexed argument. The base register is BASEREG (-1 for pc).
P points to extension word, in buffer.
ADDR is the nominal core address of that extension word. */
static unsigned char *
print_indexed (basereg, p, addr, stream)
int basereg;
unsigned char *p;
FILE *stream;
bfd_vma addr;
{
register int word;
static char *scales[] = {"", "*2", "*4", "*8"};
register int base_disp;
register int outer_disp;
char buf[40];
word = NEXTWORD (p);
/* Generate the text for the index register.
Where this will be output is not yet determined. */
sprintf (buf, "[%s.%c%s]",
reg_names[(word >> 12) & 0xf],
(word & 0x800) ? 'l' : 'w',
scales[(word >> 9) & 3]);
/* Handle the 68000 style of indexing. */
if ((word & 0x100) == 0)
{
print_base (basereg,
((word & 0x80) ? word | 0xff00 : word & 0xff)
+ ((basereg == -1) ? addr : 0),
stream);
fputs (buf, stream);
return p;
}
/* Handle the generalized kind. */
/* First, compute the displacement to add to the base register. */
if (word & 0200)
basereg = -2;
if (word & 0100)
buf[0] = 0;
base_disp = 0;
switch ((word >> 4) & 3)
{
case 2:
base_disp = NEXTWORD (p);
break;
case 3:
base_disp = NEXTLONG (p);
}
if (basereg == -1)
base_disp += addr;
/* Handle single-level case (not indirect) */
if ((word & 7) == 0)
{
print_base (basereg, base_disp, stream);
fputs (buf, stream);
return p;
}
/* Two level. Compute displacement to add after indirection. */
outer_disp = 0;
switch (word & 3)
{
case 2:
outer_disp = NEXTWORD (p);
break;
case 3:
outer_disp = NEXTLONG (p);
}
fprintf (stream, "%d(", outer_disp);
print_base (basereg, base_disp, stream);
/* If postindexed, print the closeparen before the index. */
if (word & 4)
fprintf (stream, ")%s", buf);
/* If preindexed, print the closeparen after the index. */
else
fprintf (stream, "%s)", buf);
return p;
}
/* Print a base register REGNO and displacement DISP, on STREAM.
REGNO = -1 for pc, -2 for none (suppressed). */
static void
print_base (regno, disp, stream)
int regno;
int disp;
FILE *stream;
{
if (regno == -2)
fprintf (stream, "%d", disp);
else if (regno == -1)
fprintf (stream, "0x%x", (unsigned) disp);
else
fprintf (stream, "%d(%s)", disp, reg_names[regno]);
}

387
binutils/nm.c Normal file
View File

@ -0,0 +1,387 @@
/*** nm.c -- Describe symbol table of a rel file. */
#include "sysdep.h"
#include "bfd.h"
#include "getopt.h"
#include "stab.gnu.h"
#include <ranlib.h>
PROTO(static boolean, display_file, (char *filename));
PROTO(static boolean, do_one_rel_file, (bfd *file));
PROTO(static unsigned int, filter_symbols, (bfd *file, asymbol **syms,
unsigned long symcount));
PROTO(static void, print_symbols, (bfd *file, asymbol **syms,
unsigned long symcount));
extern PROTO(int, (*sorters[2][2]), (char *x, char *y));
PROTO(static void, print_symdef_entry, (bfd * abfd));
/* Command options. */
int external_only = 0; /* print external symbols only */
int file_on_each_line = 0; /* print file name on each line */
int no_sort = 0; /* don't sort; print syms in order found */
int print_debug_syms = 0; /* print debugger-only symbols too */
int print_armap = 0; /* describe __.SYMDEF data in archive files. */
int reverse_sort = 0; /* sort in downward(alpha or numeric) order */
int sort_numerically = 0; /* sort in numeric rather than alpha order */
int undefined_only = 0; /* print undefined symbols only */
boolean print_each_filename = false; /* Ick. Used in archives. */
/* IMPORT */
extern char *program_name;
extern char *program_version;
extern char *target;
struct option long_options[] = {
{"debug-syms", 0, &print_debug_syms, 1},
{"extern-only", 0, &external_only, 1},
{"no-sort", 0, &no_sort, 1},
{"numeric-sort", 0, &sort_numerically, 1},
{"print-armap", 0, &print_armap, 1},
{"print-file-name", 0, &file_on_each_line, 1},
{"reverse-sort", 0, &reverse_sort, 1},
{"target", 2, NULL, NULL},
{"undefined-only", 0, &undefined_only, 1},
{0, 0, 0, 0}
};
/* Some error-reporting functions */
void
usage ()
{
fprintf(stderr, "nm %s\nUsage: %s [-agnoprsu] filename...\n",
program_version, program_name);
exit(0);
}
int
main (argc, argv)
int argc;
char **argv;
{
int c; /* sez which option char */
int ind = 0; /* used by getopt and ignored by us */
extern int optind; /* steps thru options */
program_name = *argv;
while ((c = getopt_long(argc, argv, "agnoprsu", long_options, &ind)) != EOF) {
switch (c) {
case 'a': print_debug_syms = 1; break;
case 'g': external_only = 1; break;
case 'n': sort_numerically = 1; break;
case 'o': file_on_each_line = 1; break;
case 'p': no_sort = 1; break;
case 'r': reverse_sort = 1; break;
case 's': print_armap = 1; break;
case 'u': undefined_only = 1; break;
case 0:
if (!strcmp("target",(long_options[option_index]).name)) {
target = optarg;
}
break; /* we've been given a long option */
default:
usage ();
}
}
/* Strangely, for the shell you should return only a nonzero value
on sucess -- the inverse of the C sense. */
/* OK, all options now parsed. If no filename specified, do a.out. */
if (optind == argc) return !display_file ("a.out");
/* We were given several filenames to do: */
while (optind < argc)
if (!display_file (argv[optind++])) return 1;
return 0;
}
/** Display a file's stats */
/* goto here is marginally cleaner than the nested if syntax */
static boolean
display_file (filename)
char *filename;
{
boolean retval = false;
bfd *file;
bfd *arfile = NULL;
file = bfd_openr(filename, target);
if (file == NULL) {
bfd_fatal (filename);
}
if (bfd_check_format(file, bfd_object)) {
retval = do_one_rel_file (file);
goto closer;
}
if (!bfd_check_format (file, bfd_archive)) {
fprintf (stderr, "%s: %s: unknown format.\n", program_name, filename);
retval = false;
goto closer;
}
printf("In archive %s:\n", filename);
if (print_armap) print_symdef_entry (file);
for (;;) {
arfile = bfd_openr_next_archived_file (file, arfile);
if (arfile == NULL) {
if (bfd_error != no_more_archived_files)
bfd_fatal (filename);
goto closer;
}
if (!bfd_check_format(arfile, bfd_object))
printf("%s: not an object file\n", arfile->filename);
else {
printf ("\n%s:\n", arfile->filename);
if (!do_one_rel_file (arfile)) return false;
}
}
closer:
if (bfd_close(file) == false)
bfd_fatal (filename);
return retval;
}
static boolean
do_one_rel_file (abfd)
bfd *abfd;
{
unsigned int storage;
asymbol **syms;
unsigned int symcount = 0;
if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
(void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
return true;
}
storage = get_symtab_upper_bound (abfd);
if (storage == 0) {
nosymz:
fprintf (stderr, "%s: Symflags set but there are none?\n",
bfd_get_filename (abfd));
exit (1);
}
syms = (asymbol **) xmalloc (storage);
symcount = bfd_canonicalize_symtab (abfd, syms);
if (symcount == 0) goto nosymz;
/* Discard the symbols we don't want to print.
It's OK to do this in place; we'll free the storage anyway
(after printing) */
symcount = filter_symbols (abfd, syms, symcount);
if (!no_sort)
qsort((char *) syms, symcount, sizeof (asymbol *),
sorters[sort_numerically][reverse_sort]);
if (print_each_filename && !file_on_each_line)
printf("\n%s:\n", bfd_get_filename(abfd));
print_symbols (abfd, syms, symcount);
free (syms);
return true;
}
/* Symbol-sorting predicates */
#define valueof(x) ((x)->section ? (x)->section->vma + (x)->value : (x)->value)
int
numeric_forward (x, y)
char *x;
char *y;
{
return (valueof(*(asymbol **)x) - valueof(*(asymbol **) y));;
}
int
numeric_reverse (x, y)
char *x;
char *y;
{
return (valueof(*(asymbol **)y) - valueof(*(asymbol **) x));
}
int
non_numeric_forward (x, y)
char *x;
char *y;
{
char *xn = (*(asymbol **) x)->name;
char *yn = (*(asymbol **) y)->name;
return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) :
((yn == NULL) ? 1 : strcmp (xn, yn)));
}
int
non_numeric_reverse (x, y)
char *x;
char *y;
{
return -(non_numeric_forward (x, y));
}
int (*sorters[2][2])() = {
{non_numeric_forward, non_numeric_reverse},
{numeric_forward, numeric_reverse},
};
/* Choose which symbol entries to print;
compact them downward to get rid of the rest.
Return the number of symbols to be printed. */
static unsigned int
filter_symbols (abfd, syms, symcount)
bfd *abfd;
asymbol **syms;
unsigned long symcount;
{
asymbol **from, **to;
unsigned int dst_count = 0;
unsigned int src_count;
for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
int keep = 0;
flagword flags = (from[src_count])->flags;
if (undefined_only) {
keep = (flags & BSF_UNDEFINED);
} else if (external_only) {
keep = ((flags & BSF_GLOBAL) || (flags & BSF_UNDEFINED) ||
(flags & BSF_FORT_COMM));
} else {
keep = 1;
}
if (!print_debug_syms && ((flags & BSF_DEBUGGING) != 0)) {
keep = 0;
}
if (keep) {
to[dst_count++] = from[src_count];
}
}
return dst_count;
}
/* Return a lower-case character corresponding to the symbol class of sym */
char
decode_symclass (sym)
asymbol *sym;
{
flagword flags = sym->flags;
if ((sym->value == 0) && (sym->section != NULL))
/* Huh? All section names don't begin with "." */
return (sym->section->name)[1];
if (flags & BSF_FORT_COMM) return 'C';
if (flags & BSF_UNDEFINED) return 'U';
if (flags & BSF_ABSOLUTE) return 'a';
if ( (flags & BSF_GLOBAL) || (flags & BSF_LOCAL) ){
if ( !strcmp(sym->section->name, ".text") ){
return 't';
} else if ( !strcmp(sym->section->name, ".data") ){
return 'd';
} else if ( !strcmp(sym->section->name, ".bss") ){
return 'b';
} else {
return 'o';
}
}
/* We don't have to handle these cases just yet, but we will soon:
N_SETV: 'v';
N_SETA: 'l';
N_SETT: 'x';
N_SETD: 'z';
N_SETB: 's';
N_INDR: 'i';
*/
return '?';
}
static void
print_symbols (abfd, syms, symcount)
bfd *abfd;
asymbol **syms;
unsigned long symcount;
{
asymbol **sym = syms, **end = syms + symcount;
char class;
for (; sym < end; ++sym) {
if (file_on_each_line) printf("%s:", bfd_get_filename(abfd));
if (undefined_only) {
if ((*sym)->flags & BSF_UNDEFINED)
puts ((*sym)->name);
}
else {
asymbol *p = *sym;
if (p) {
class = decode_symclass (p);
if (p->flags & BSF_GLOBAL)
class = toupper (class);
if (p->value || ((p->flags & BSF_UNDEFINED) != BSF_UNDEFINED))
printf ("%08lx ", (p->section ? p->value + p->section->vma : p->value));
else fputs (" ", stdout);
printf ("%c %s\n", class, p->name);
}
}
}
}
static void
print_symdef_entry (abfd)
bfd * abfd;
{
symindex idx = BFD_NO_MORE_SYMBOLS;
carsym *thesym;
boolean everprinted = false;
for (idx = bfd_get_next_mapent (abfd, idx, &thesym);
idx != BFD_NO_MORE_SYMBOLS;
idx = bfd_get_next_mapent (abfd, idx, &thesym)) {
bfd *elt;
if (!everprinted) {
printf ("\nArchive index:\n");
everprinted = true;
}
elt = bfd_get_elt_at_index (abfd, idx);
if (thesym->name != (char *)NULL) {
printf ("%s in %s\n", thesym->name, bfd_get_filename (elt));
}
}
}

714
binutils/objdump.c Normal file
View File

@ -0,0 +1,714 @@
/*** objdump.c -- dump information about an object file. */
/* Copyright (C) 1990, 1991 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Diddler.
BFD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
BFD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BFD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:26:48 gumby
Initial revision
* Revision 1.2 1991/03/15 18:34:14 rich
* foo
*
* Revision 1.1 1991/03/13 00:34:19 chrisb
* Initial revision
*
* Revision 1.9 1991/03/09 04:36:33 rich
* Modified Files:
* sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
* binutils.h
*
* Pulled sysdep.h out of bfd.h.
*
* Revision 1.8 1991/03/09 03:42:01 rich
* Modified Files:
* Makefile alloca.c ar.c i960-pinsn.c nm.c objdump.c ostrip.c
* strip.c
*
* Ports for intel960 group Portland.
*
* Revision 1.7 1991/03/08 21:54:47 rich
* Modified Files:
* Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
* i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
* sparc-pinsn.c strip.c
*
* Verifying Portland tree with steve's last changes. Also, some partial
* porting.
*
* Revision 1.6 1991/03/08 07:46:26 sac
* Added -l option to disassembly - prints line numbers too.
*
* Revision 1.5 1991/03/07 21:50:24 sac
* More intelligent reloc printing
*
* Revision 1.4 1991/03/05 16:36:54 sac
* Fixed bug where empty symbols would print (null) on suns and crash elsewhere.
*
*/
/*
* Until there is other documentation, refer to the manual page dump(1) in
* the system 5 program's reference manual
*/
#include "sysdep.h"
#include "bfd.h"
#include "getopt.h"
#include <stdio.h>
#include <ctype.h>
char *malloc();
char *realloc();
char *xmalloc();
char *default_target = NULL; /* default at runtime */
char *program_name = NULL;
int dump_section_contents; /* -s */
int dump_section_headers; /* -h */
boolean dump_file_header; /* -f */
int dump_symtab; /* -t */
int dump_reloc_info; /* -r */
int dump_ar_hdrs; /* -a */
int with_line_numbers; /* -l */
boolean disassemble; /* -d */
char *only;
PROTO (void, display_file, (char *filename, char *target));
PROTO (void, dump_data, (bfd *abfd));
PROTO (void, dump_relocs, (bfd *abfd));
PROTO (void, dump_symbols, (bfd *abfd));
PROTO (void, print_arelt_descr, (bfd *abfd, boolean verbose));
char *machine = (char *)NULL;
asymbol **syms;
asymbol **syms2;
unsigned int storage;
unsigned int symcount = 0;
void
usage ()
{
fprintf (stderr,
"usage: %s [-ahfdrtxsl] [-m machine] [-j section_name] obj ...\n",
program_name);
exit (1);
}
static struct option long_options[] =
{{"syms", 0, &dump_symtab, 1},
{"reloc", 0, &dump_reloc_info, 1},
{"header", 0, &dump_section_headers, 1},
{0, 0, 0, 0}};
static void
dump_headers(abfd)
bfd *abfd;
{
asection *section;
for (section = abfd->sections;
section != (asection *) NULL;
section = section->next)
{
char *comma = "";
#define PF(x,y) \
if (section->flags & x) { printf("%s%s",comma,y); comma = ", "; }
printf("SECTION %d [%s]\t: size %08x",
section->index,
section->name,
(unsigned) section->size);
printf(" vma %08lx align 2**%2u\n ",
section->vma,
section->alignment_power);
PF(SEC_ALLOC,"ALLOC");
PF(SEC_LOAD,"LOAD");
PF(SEC_RELOC,"RELOC");
PF(SEC_BALIGN,"BALIGN");
PF(SEC_READONLY,"READONLY");
PF(SEC_CODE,"CODE");
PF(SEC_DATA,"DATA");
PF(SEC_ROM,"ROM");
printf("\n");
#undef PF
}
}
static asymbol **
slurp_symtab(abfd)
bfd *abfd;
{
asymbol **sy;
if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) {
(void) printf ("No symbols in \"%s\".\n", bfd_get_filename (abfd));
return(NULL);
}
storage = get_symtab_upper_bound (abfd);
if (storage) {
sy = (asymbol **) malloc (storage);
if (sy == NULL) {
fprintf (stderr, "%s: out of memory.\n", program_name);
exit (1);
}
}
symcount = bfd_canonicalize_symtab (abfd, sy);
return sy;
}
/* Sort symbols into value order */
static int comp(ap,bp)
asymbol **ap;
asymbol **bp;
{
asymbol *a = *ap;
asymbol *b = *bp;
int diff;
if ( a->name== (char *)NULL || (a->flags &( BSF_DEBUGGING| BSF_UNDEFINED) ))
a->the_bfd = 0;
if ( b->name== (char *)NULL || (b->flags &( BSF_DEBUGGING|BSF_UNDEFINED)))
b->the_bfd =0;
diff = a->the_bfd - b->the_bfd;
if (diff) {
return -diff;
}
diff = a->value - b->value;
if (diff) {
return diff;
}
return a->section - b->section;
}
/* Print the supplied address symbolically if possible */
void
print_address(vma, stream)
bfd_vma vma;
FILE *stream;
{
/* Perform a binary search looking for the closest symbol to
the required value */
unsigned int min = 0;
unsigned int max = symcount;
unsigned int thisplace = 1;
unsigned int oldthisplace ;
int vardiff;
if (symcount == 0)
fprintf(stream,"%08lx", vma);
else {
while (true) {
oldthisplace = thisplace;
thisplace = (max + min )/2 ;
if (thisplace == oldthisplace) break;
vardiff = syms[thisplace]->value - vma;
if (vardiff) {
if (vardiff > 0) {
max = thisplace;
}
else {
min = thisplace;
}
}
else {
/* Totally awesome! the exact right symbol */
fprintf(stream,"%08lx (%s)", vma, syms[thisplace]->name);
return;
}
}
/* We've run out of places to look, print the symbol before this one */
/* see if this or the symbol before describes this location the best */
if (thisplace != 0) {
if (syms[thisplace-1]->value - vma >
syms[thisplace]->value-vma) {
/* Previous symbol is in correct section and is closer */
thisplace --;
}
}
{
char *section_name;
asection *sec = syms[thisplace]->section;
if (sec) {
section_name = sec->name;
}
else {
section_name = "abs";
}
}
if (syms[thisplace]->value > vma) {
fprintf(stream,"%08lx (%s-%lx)", vma, syms[thisplace]->name,
syms[thisplace]->value - vma);
}
else {
fprintf(stream,"%08lx (%s+%lx)", vma,
syms[thisplace]->name,
vma - syms[thisplace]->value);
}
}
}
void
disassemble_data(abfd)
bfd *abfd;
{
bfd_byte *data = NULL;
unsigned int datasize = 0;
unsigned int i;
int (*print)() ;
int print_insn_m68k();
int print_insn_i960();
int print_insn_sparc();
enum bfd_architecture a;
unsigned long m;
asection *section;
/* Replace symbol section relative values with abs values */
for (i = 0; i < symcount; i++) {
if (syms[i]->section != (asection *)NULL) {
syms[i]->value += syms[i]->section->vma;
}
}
/* We keep a copy of the symbols in the original order */
syms2 = slurp_symtab(abfd);
/* Sort the symbols into section and symbol order */
(void) qsort(syms, symcount, sizeof(asymbol *), comp);
/* Find the first useless symbol */
{ unsigned int i;
for (i =0; i < symcount; i++) {
if (syms[i]->the_bfd == 0) {
symcount =i;
break;
}
}
}
if (machine!= (char *)NULL) {
if (bfd_scan_arch_mach(machine, &a, &m) == false) {
fprintf(stderr,"%s: Can't use supplied machine %s\n",
program_name,
machine);
exit(1);
}
}
else {
a = bfd_get_architecture(abfd);
}
switch (a) {
case bfd_arch_sparc:
print = print_insn_sparc;
break;
case bfd_arch_m68k:
print = print_insn_m68k;
break;
case bfd_arch_i960:
print = print_insn_i960;
break;
default:
fprintf(stderr,"%s: Can't disassemble for architecture %s\n",
program_name,
bfd_printable_arch_mach(bfd_get_architecture(abfd),0));
exit(1);
}
for (section = abfd->sections;
section != (asection *)NULL;
section = section->next) {
if (only == (char *)NULL || strcmp(only,section->name) == 0){
printf("Disassembly of section %s:\n", section->name);
if (section->size == 0) continue;
data = (bfd_byte *)malloc(section->size);
if (data == (bfd_byte *)NULL) {
fprintf (stderr, "%s: memory exhausted.\n", program_name);
exit (1);
}
datasize = section->size;
bfd_get_section_contents (abfd, section, data, 0, section->size);
i = 0;
while ((size_t)i <section->size) {
if (with_line_numbers) {
static prevline;
char *filename;
char *functionname;
int line;
bfd_find_nearest_line(abfd,
section,
syms,
section->vma + i,
&filename,
&functionname,
&line);
if (filename && functionname && line && line != prevline) {
printf("%s:%d\n", filename, line);
prevline = line;
}
}
print_address(section->vma + i, stdout);
printf(" ");
i += print(section->vma + i,
data + i,
stdout);
putchar ('\n') ;
}
free(data);
}
}
}
void
display_bfd (abfd)
bfd *abfd;
{
if (!bfd_check_format (abfd, bfd_object)) {
fprintf (stderr,"%s: %s not an object file\n", program_name,
abfd->filename);
return;
}
printf ("\n%s: file format %s\n", abfd->filename, abfd->xvec->name);
if (dump_ar_hdrs) print_arelt_descr (abfd, true);
if (dump_file_header) {
char *comma = "";
printf("architecture: %s, ",
bfd_printable_arch_mach (bfd_get_architecture (abfd),
bfd_get_machine (abfd)));
printf("flags 0x%08x:\n", abfd->flags);
#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";}
PF(HAS_RELOC, "HAS_RELOC");
PF(EXEC_P, "EXEC_P");
PF(HAS_LINENO, "HAS_LINENO");
PF(HAS_DEBUG, "HAS_DEBUG");
PF(HAS_SYMS, "HAS_SYMS");
PF(HAS_LOCALS, "HAS_LOCALS");
PF(DYNAMIC, "DYNAMIC");
PF(WP_TEXT, "WP_TEXT");
PF(D_PAGED, "D_PAGED");
printf("\nstart address 0x%08lx", abfd->start_address);
}
printf("\n");
if (dump_section_headers)
dump_headers(abfd);
if (dump_symtab || dump_reloc_info || disassemble) {
syms = slurp_symtab(abfd);
}
if (dump_symtab) dump_symbols (abfd);
if (dump_reloc_info) dump_relocs(abfd);
if (dump_section_contents) dump_data (abfd);
if (disassemble) disassemble_data(abfd);
}
void
display_file (filename, target)
char *filename;
char *target;
{
bfd *file, *arfile = (bfd *) NULL;
file = bfd_openr (filename, target);
if (file == NULL) {
bfd_perror (filename);
return;
}
if (bfd_check_format (file, bfd_archive) == true) {
printf ("In archive %s:\n", bfd_get_filename (file));
for(;;) {
bfd_error = no_error;
arfile = bfd_openr_next_archived_file (file, arfile);
if (arfile == NULL) {
if (bfd_error != no_more_archived_files)
bfd_perror (bfd_get_filename(file));
return;
}
display_bfd (arfile);
/* Don't close the archive elements; we need them for next_archive */
}
}
else
display_bfd(file);
bfd_close(file);
}
/* Actually display the various requested regions */
void
dump_data (abfd)
bfd *abfd;
{
asection *section;
bfd_byte *data ;
unsigned int datasize = 0;
size_t i;
for (section = abfd->sections; section != NULL; section =
section->next) {
int onaline = 16;
if (only == (char *)NULL ||
strcmp(only,section->name) == 0){
printf("Contents of section %s:\n", section->name);
if (section->size == 0) continue;
data = (bfd_byte *)malloc(section->size);
if (data == (bfd_byte *)NULL) {
fprintf (stderr, "%s: memory exhausted.\n", program_name);
exit (1);
}
datasize = section->size;
bfd_get_section_contents (abfd, section, data, 0, section->size);
for (i= 0; i < section->size; i += onaline) {
size_t j;
printf(" %04lx ", i + section->vma);
for (j = i; j < i+ onaline; j++) {
if (j < section->size)
printf("%02x", (unsigned)(data[j]));
else
printf(" ");
if ((j & 3 ) == 3) printf(" ");
}
printf(" ");
for (j = i; j < i+onaline ; j++) {
if (j >= section->size)
printf(" ");
else
printf("%c", isprint(data[j]) ?data[j] : '.');
}
putchar ('\n');
}
}
free (data);
}
}
/* Should perhaps share code and display with nm? */
void
dump_symbols (abfd)
bfd *abfd;
{
unsigned int count;
asymbol **current = syms;
printf("SYMBOL TABLE:\n");
for (count = 0; count < symcount; count++) {
if ((*current)->the_bfd) {
bfd_print_symbol((*current)->the_bfd,
stdout,
*current, bfd_print_symbol_all_enum);
printf("\n");
}
current++;
}
printf("\n");
printf("\n");
}
void
dump_relocs(abfd)
bfd *abfd;
{
arelent **relpp;
unsigned int relcount;
asection *a;
for (a = abfd->sections; a != (asection *)NULL; a = a->next) {
printf("RELOCATION RECORDS FOR [%s]:",a->name);
if (get_reloc_upper_bound(abfd, a) == 0) {
printf(" (none)\n\n");
}
else {
arelent **p;
relpp = (arelent **) xmalloc( get_reloc_upper_bound(abfd,a) );
relcount = bfd_canonicalize_reloc(abfd,a,relpp, syms);
if (relcount == 0) {
printf(" (none)\n\n");
}
else {
printf("\n");
printf("OFFSET TYPE VALUE \n");
for (p =relpp; *p != (arelent *)NULL; p++) {
arelent *q = *p;
char *sym_name;
char *section_name = q->section == (asection *)NULL ? "*abs" :
q->section->name;
if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
sym_name = (*(q->sym_ptr_ptr))->name ;
}
else {
sym_name = 0;
}
if (sym_name) {
printf("%08lx %-8s %s",
q->address,
q->howto->name,
sym_name);
}
else {
printf("%08lx %-8s [%s]",
q->address,
q->howto->name,
section_name);
}
if (q->addend) {
printf("+0x%lx(%ld)", q->addend, (long) q->addend);
}
printf("\n");
}
printf("\n\n");
free(relpp);
}
}
}
}
/** main and like trivia */
int
main (argc, argv)
int argc;
char **argv;
{
int c;
extern int optind;
extern char *optarg;
char *target = default_target;
boolean seenflag = false;
int ind = 0;
program_name = *argv;
while ((c = getopt_long (argc, argv, "b:m:dlfahrtxsj:", long_options, &ind))
!= EOF) {
seenflag = true;
switch (c) {
case 'm':
machine = optarg;
break;
case 'j':
only = optarg;
break;
case 'l':
with_line_numbers = 1;
break;
case 'b':
target = optarg;
break;
case 'f':
dump_file_header = true;
break;
case 'x':
dump_symtab = 1;
dump_reloc_info = 1;
dump_file_header = true;
dump_ar_hdrs = 1;
dump_section_headers = 1;
break;
case 0 : break; /* we've been given a long option */
case 't': dump_symtab = 1; break;
case 'd': disassemble = true ; break;
case 's': dump_section_contents = 1; break;
case 'r': dump_reloc_info = 1; break;
case 'a': dump_ar_hdrs = 1; break;
case 'h': dump_section_headers = 1; break;
default:
usage ();
}
}
if (seenflag == false)
usage ();
if (optind == argc)
display_file ("a.out", target);
else
for (; optind < argc;)
display_file (argv[optind++], target);
return 0;
}

320
binutils/size.c Normal file
View File

@ -0,0 +1,320 @@
/*** size.c -- report size of various sections of an executable file */
/* Extensions/incompatibilities:
o - BSD output has filenames at the end.
o - BSD output can appear in different radicies.
o - SysV output has less redundant whitespace. Filename comes at end.
o - SysV output doesn't show VMA which is always the same as the PMA.
o - We also handle core files.
o - We also handle archives.
If you write shell scripts which manipulate this info then you may be
out of luck; there's no +predantic switch.
*/
#include "sysdep.h"
#include "bfd.h"
#include "getopt.h"
#ifndef BSD_DEFAULT
#define BSD_DEFAULT 1
#endif
PROTO(void, display_file, (char *filename));
PROTO(void, print_sizes, (bfd *file));
/* Various program options */
enum {decimal, octal, hex} radix = decimal;
int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output */
int show_version = 0;
int show_help = 0;
/* IMPORTS */
extern char *program_version;
extern char *program_name;
extern char *target;
/** main and like trivia */
void
usage ()
{
fprintf (stderr, "size %s\nUsage: %s -{dox}{AB}V files ...\n",
program_version, program_name);
fputs("\t+radix={8|10|16} -- select appropriate output radix.\n\
\t-d -- output in decimal\n\
\t-o -- output in octal\n\
\t-x -- output in hex", stderr);
fputs("\t+format={Berkeley|SysV} -- select display format.\n\
\t-A -- SysV(AT&T) format\n\
\t-B -- BSD format", stderr);
#if BSD_DEFAULT
fputs("\t (Default is +format=Berkeley)", stderr);
#else
fputs("\t (Default is +format=SysV)", stderr);
#endif
fputs("\t-V, +version -- display program version, etc.\n\
\t+help -- this message\n", stderr);
exit(1);
}
struct option long_options[] = {{"radix", 1, 0, 0},
{"format", 1, 0, 0},
{"version", 0, &show_version, 1},
{"target", 2, NULL, NULL},
{"help", 0, &show_help, 1},
{0, 0, 0, 0}};
int
main (argc, argv)
int argc;
char **argv;
{
int temp;
int c; /* sez which option char */
int option_index = 0;
extern int optind; /* steps thru options */
program_name = *argv;
while ((c = getopt_long(argc, argv, "ABVdox", long_options,
&option_index)) != EOF)
switch(c) {
case 0:
if (!strcmp("format",(long_options[option_index]).name)) {
switch(*optarg) {
case 'B': case 'b': berkeley_format = 1; break;
case 'S': case 's': berkeley_format = 0; break;
default: printf("Unknown option to +format: %s\n", optarg);
usage();
}
break;
}
if (!strcmp("target",(long_options[option_index]).name)) {
target = optarg;
break;
}
if (!strcmp("radix",(long_options[option_index]).name)) {
#ifdef ANSI_LIBRARIES
temp = strtol(optarg, NULL, 10);
#else
temp = atol(optarg);
#endif
switch(temp) {
case 10: radix = decimal; break;
case 8: radix = octal; break;
case 16: radix = hex; break;
default: printf("Unknown radix: %s\n", optarg);
usage();
}
}
break;
case 'A': berkeley_format = 0; break;
case 'B': berkeley_format = 1; break;
case 'V': show_version = 1; break;
case 'd': radix = decimal; break;
case 'x': radix = hex; break;
case 'o': radix = octal; break;
case '?': usage();
}
if (show_version) printf("%s version %s\n", program_name, program_version);
if (show_help) usage();
if (berkeley_format)
#if 0 /* intel doesn't like bss/stk b/c they don't gave core files */
puts((radix == octal) ? "text\tdata\tbss/stk\toct\thex\tfilename" :
"text\tdata\tbss/stk\tdec\thex\tfilename");
#else
puts((radix == octal) ? "text\tdata\tbss\toct\thex\tfilename" :
"text\tdata\tbss\tdec\thex\tfilename");
#endif
if (optind == argc)
display_file ("a.out");
else
for (; optind < argc;)
display_file (argv[optind++]);
return 0;
}
/** Display a file's stats */
void
display_bfd (abfd)
bfd *abfd;
{
char *core_cmd;
if (bfd_check_format(abfd, bfd_archive)) return;
if (bfd_check_format(abfd, bfd_object)) {
print_sizes(abfd);
goto done;
}
if (bfd_check_format(abfd, bfd_core)) {
print_sizes(abfd);
fputs(" (core file", stdout);
core_cmd = bfd_core_file_failing_command(abfd);
if (core_cmd) printf(" invoked as %s", core_cmd);
puts(")");
goto done;
}
printf("Unknown file format: %s.", bfd_get_filename(abfd));
done:
printf("\n");
return;
}
void
display_file(filename)
char *filename;
{
bfd *file, *arfile = (bfd *) NULL;
file = bfd_openr (filename, target);
if (file == NULL) {
bfd_perror (filename);
return;
}
if (bfd_check_format(file, bfd_archive) == true) {
for(;;) {
bfd_error = no_error;
arfile = bfd_openr_next_archived_file (file, arfile);
if (arfile == NULL) {
if (bfd_error != no_more_archived_files)
bfd_perror (bfd_get_filename (file));
return;
}
display_bfd (arfile);
/* Don't close the archive elements; we need them for next_archive */
}
}
else
display_bfd (file);
bfd_close (file);
}
/* This is what lexical functions are for */
void
lprint_number (width, num)
int width, num;
{
printf ((radix == decimal ? "%-*d\t" :
((radix == octal) ? "%-*o\t" : "%-*x\t")), width, num);
}
void
rprint_number(width, num)
int width, num;
{
printf ((radix == decimal ? "%*d\t" :
((radix == octal) ? "%*o\t" : "%*x\t")), width, num);
}
static char *bss_section_name = ".bss";
static char *data_section_name = ".data";
static char *stack_section_name = ".stack";
static char *text_section_name = ".text";
void print_berkeley_format(abfd)
bfd *abfd;
{
sec_ptr bsssection = NULL;
sec_ptr datasection = NULL;
sec_ptr textsection = NULL;
unsigned long bsssize = 0;
unsigned long datasize = 0;
unsigned long textsize = 0;
unsigned long total = 0;
if ((textsection = bfd_get_section_by_name (abfd, text_section_name))
!= NULL) {
textsize = bfd_section_size (abfd, textsection);
}
if ((datasection = bfd_get_section_by_name (abfd, data_section_name))
!= NULL) {
datasize = bfd_section_size(abfd, datasection);
}
if (bfd_get_format (abfd) == bfd_object) {
if ((bsssection = bfd_get_section_by_name (abfd, bss_section_name))
!= NULL) {
bsssize = bfd_section_size(abfd, bsssection);
}
} else {
if ((bsssection = bfd_get_section_by_name (abfd, stack_section_name))
!= NULL) {
bsssize = bfd_section_size(abfd, bsssection);
}
}
total = textsize + datasize + bsssize;
lprint_number (7, textsize);
lprint_number (7, datasize);
lprint_number (7, bsssize);
printf (((radix == octal) ? "%-7o\t%-7x\t" : "%-7d\t%-7x\t"), total, total);
fputs(bfd_get_filename(abfd), stdout);
if (abfd->my_archive) printf (" (ex %s)", abfd->my_archive->filename);
}
/* I REALLY miss lexical functions! */
int svi_total = 0;
void
sysv_internal_printer(file, sec)
bfd *file;
sec_ptr sec;
{
int size = bfd_section_size (file, sec);
svi_total += size;
printf ("%-12s", bfd_section_name(file, sec));
rprint_number (8, size);
printf(" ");
rprint_number (8, bfd_section_vma(file, sec));
printf ("\n");
}
void
print_sysv_format(file)
bfd *file;
{
svi_total = 0;
printf ("%s ", bfd_get_filename (file));
if (file->my_archive) printf (" (ex %s)", file->my_archive->filename);
puts(":\nsection\t\tsize\t addr");
bfd_map_over_sections (file, sysv_internal_printer, NULL);
printf("Total ");
rprint_number(8, svi_total);
printf("\n"); printf("\n");
}
void
print_sizes(file)
bfd *file;
{
if (berkeley_format)
print_berkeley_format(file);
else print_sysv_format(file);
}

490
binutils/sparc-pinsn.c Normal file
View File

@ -0,0 +1,490 @@
/* disassemble sparc instructions for objdump
Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
This file is part of the binutils.
The binutils are free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
The binutils are distributed in the hope that they will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the binutils; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id$
$Log$
Revision 1.1 1991/03/21 21:26:55 gumby
Initial revision
* Revision 1.1 1991/03/13 00:34:40 chrisb
* Initial revision
*
* Revision 1.3 1991/03/09 04:36:31 rich
* Modified Files:
* sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
* binutils.h
*
* Pulled sysdep.h out of bfd.h.
*
* Revision 1.2 1991/03/08 21:54:53 rich
* Modified Files:
* Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
* i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
* sparc-pinsn.c strip.c
*
* Verifying Portland tree with steve's last changes. Also, some partial
* porting.
*
* Revision 1.1 1991/02/22 16:48:04 sac
* Initial revision
*
*/
#include <stdio.h>
#include "sysdep.h"
#include "bfd.h"
#include "sparc-opcode.h"
extern int fputs();
extern int print_address();
static char *reg_names[] =
{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr" };
#define freg_names (&reg_names[4 * 8])
union sparc_insn
{
unsigned long int code;
struct
{
unsigned int OP:2;
#define op ldst.OP
unsigned int RD:5;
#define rd ldst.RD
unsigned int op3:6;
unsigned int RS1:5;
#define rs1 ldst.RS1
unsigned int i:1;
unsigned int ASI:8;
#define asi ldst.ASI
unsigned int RS2:5;
#define rs2 ldst.RS2
#define shcnt rs2
} ldst;
struct
{
unsigned int OP:2, RD:5, op3:6, RS1:5, i:1;
unsigned int IMM13:13;
#define imm13 IMM13.IMM13
} IMM13;
struct
{
unsigned int OP:2;
unsigned int a:1;
unsigned int cond:4;
unsigned int op2:3;
unsigned int DISP22:22;
#define disp22 branch.DISP22
} branch;
#define imm22 disp22
struct
{
unsigned int OP:2;
unsigned int DISP30:30;
#define disp30 call.DISP30
} call;
};
/* Nonzero if INSN is the opcode for a delayed branch. */
static int
is_delayed_branch (insn)
union sparc_insn insn;
{
unsigned int i;
for (i = 0; i < NUMOPCODES; ++i)
{
const struct sparc_opcode *opcode = &sparc_opcodes[i];
if ((opcode->match & insn.code) == opcode->match
&& (opcode->lose & insn.code) == 0
&& (opcode->delayed))
return 1;
}
return 0;
}
static int opcodes_sorted = 0;
/* Print one instruction from MEMADDR on STREAM. */
int
print_insn_sparc (memaddr, buffer, stream)
bfd_vma memaddr;
bfd_byte *buffer;
FILE *stream;
{
union sparc_insn insn;
register unsigned int i;
if (!opcodes_sorted)
{
static int compare_opcodes ();
qsort ((char *) sparc_opcodes, NUMOPCODES,
sizeof (sparc_opcodes[0]), compare_opcodes);
opcodes_sorted = 1;
}
memcpy(&insn,buffer, sizeof (insn));
for (i = 0; i < NUMOPCODES; ++i)
{
const struct sparc_opcode *opcode = &sparc_opcodes[i];
if ((opcode->match & insn.code) == opcode->match
&& (opcode->lose & insn.code) == 0)
{
/* Nonzero means that we have found an instruction which has
the effect of adding or or'ing the imm13 field to rs1. */
int imm_added_to_rs1 = 0;
/* Nonzero means that we have found a plus sign in the args
field of the opcode table. */
int found_plus = 0;
/* Do we have an 'or' instruction where rs1 is the same
as rsd, and which has the i bit set? */
if (opcode->match == 0x80102000
&& insn.rs1 == insn.rd)
imm_added_to_rs1 = 1;
if (index (opcode->args, 'S') != 0)
/* Reject the special case for `set'.
The real `sethi' will match. */
continue;
if (insn.rs1 != insn.rd
&& index (opcode->args, 'r') != 0)
/* Can't do simple format if source and dest are different. */
continue;
fputs (opcode->name, stream);
{
register const char *s;
if (opcode->args[0] != ',')
fputs (" ", stream);
for (s = opcode->args; *s != '\0'; ++s)
{
if (*s == ',')
{
fputs (",", stream);
++s;
if (*s == 'a')
{
fputs ("a", stream);
++s;
}
fputs (" ", stream);
}
switch (*s)
{
case '+':
found_plus = 1;
/* note fall-through */
default:
fprintf (stream, "%c", *s);
break;
case '#':
fputs ("0", stream);
break;
#define reg(n) fprintf (stream, "%%%s", reg_names[n])
case '1':
case 'r':
reg (insn.rs1);
break;
case '2':
reg (insn.rs2);
break;
case 'd':
reg (insn.rd);
break;
#undef reg
#define freg(n) fprintf (stream, "%%%s", freg_names[n])
case 'e':
freg (insn.rs1);
break;
case 'f':
freg (insn.rs2);
break;
case 'g':
freg (insn.rd);
break;
#undef freg
#define creg(n) fprintf (stream, "%%c%u", (unsigned int) (n))
case 'b':
creg (insn.rs1);
break;
case 'c':
creg (insn.rs2);
break;
case 'D':
creg (insn.rd);
break;
#undef creg
case 'h':
fprintf (stream, "%%hi(%#x)",
(unsigned int) insn.imm22 << 10);
break;
case 'i':
{
/* We cannot trust the compiler to sign-extend
when extracting the bitfield, hence the shifts. */
int imm = ((int) insn.imm13 << 19) >> 19;
/* Check to see whether we have a 1+i, and take
note of that fact.
Note: because of the way we sort the table,
we will be matching 1+i rather than i+1,
so it is OK to assume that i is after +,
not before it. */
if (found_plus)
imm_added_to_rs1 = 1;
if (imm <= 9)
fprintf (stream, "%d", imm);
else
fprintf (stream, "%#x", (unsigned) imm);
}
break;
case 'L':
print_address ((bfd_vma) memaddr + insn.disp30 * 4,
stream);
break;
case 'l':
if ((insn.code >> 22) == 0)
/* Special case for `unimp'. Don't try to turn
it's operand into a function offset. */
fprintf (stream, "%#x",
(unsigned) (((int) insn.disp22 << 10) >> 10));
else
/* We cannot trust the compiler to sign-extend
when extracting the bitfield, hence the shifts. */
print_address ((bfd_vma)
(memaddr
+ (((int) insn.disp22 << 10) >> 10) * 4),
stream);
break;
case 'A':
fprintf (stream, "(%d)", (int) insn.asi);
break;
case 'C':
fputs ("%csr", stream);
break;
case 'F':
fputs ("%fsr", stream);
break;
case 'p':
fputs ("%psr", stream);
break;
case 'q':
fputs ("%fq", stream);
break;
case 'Q':
fputs ("%cq", stream);
break;
case 't':
fputs ("%tbr", stream);
break;
case 'w':
fputs ("%wim", stream);
break;
case 'y':
fputs ("%y", stream);
break;
}
}
}
/* If we are adding or or'ing something to rs1, then
check to see whether the previous instruction was
a sethi to the same register as in the sethi.
If so, attempt to print the result of the add or
or (in this context add and or do the same thing)
and its symbolic value. */
if (imm_added_to_rs1)
{
union sparc_insn prev_insn;
int errcode;
memcpy(&prev_insn, buffer -4, sizeof (prev_insn));
if (errcode == 0)
{
/* If it is a delayed branch, we need to look at the
instruction before the delayed branch. This handles
sequences such as
sethi %o1, %hi(_foo), %o1
call _printf
or %o1, %lo(_foo), %o1
*/
if (is_delayed_branch (prev_insn))
memcpy(&prev_insn, buffer - 8, sizeof(prev_insn));
}
/* If there was a problem reading memory, then assume
the previous instruction was not sethi. */
if (errcode == 0)
{
/* Is it sethi to the same register? */
if ((prev_insn.code & 0xc1c00000) == 0x01000000
&& prev_insn.rd == insn.rs1)
{
fprintf (stream, "\t! ");
/* We cannot trust the compiler to sign-extend
when extracting the bitfield, hence the shifts. */
print_address (((int) prev_insn.imm22 << 10)
| (insn.imm13 << 19) >> 19, stream);
}
}
}
return sizeof (insn);
}
}
fprintf ("%#8x", insn.code);
return sizeof (insn);
}
/* Compare opcodes A and B. */
static int
compare_opcodes (a, b)
char *a, *b;
{
struct sparc_opcode *op0 = (struct sparc_opcode *) a;
struct sparc_opcode *op1 = (struct sparc_opcode *) b;
unsigned long int match0 = op0->match, match1 = op1->match;
unsigned long int lose0 = op0->lose, lose1 = op1->lose;
register unsigned int i;
/* If a bit is set in both match and lose, there is something
wrong with the opcode table. */
if (match0 & lose0)
{
fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op0->name, match0, lose0);
op0->lose &= ~op0->match;
lose0 = op0->lose;
}
if (match1 & lose1)
{
fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op1->name, match1, lose1);
op1->lose &= ~op1->match;
lose1 = op1->lose;
}
/* Because the bits that are variable in one opcode are constant in
another, it is important to order the opcodes in the right order. */
for (i = 0; i < 32; ++i)
{
unsigned long int x = 1 << i;
int x0 = (match0 & x) != 0;
int x1 = (match1 & x) != 0;
if (x0 != x1)
return x1 - x0;
}
for (i = 0; i < 32; ++i)
{
unsigned long int x = 1 << i;
int x0 = (lose0 & x) != 0;
int x1 = (lose1 & x) != 0;
if (x0 != x1)
return x1 - x0;
}
/* They are functionally equal. So as long as the opcode table is
valid, we can put whichever one first we want, on aesthetic grounds. */
{
int length_diff = strlen (op0->args) - strlen (op1->args);
if (length_diff != 0)
/* Put the one with fewer arguments first. */
return length_diff;
}
/* Put 1+i before i+1. */
{
char *p0 = (char *) index(op0->args, '+');
char *p1 = (char *) index(op1->args, '+');
if (p0 && p1)
{
/* There is a plus in both operands. Note that a plus
sign cannot be the first character in args,
so the following [-1]'s are valid. */
if (p0[-1] == 'i' && p1[1] == 'i')
/* op0 is i+1 and op1 is 1+i, so op1 goes first. */
return 1;
if (p0[1] == 'i' && p1[-1] == 'i')
/* op0 is 1+i and op1 is i+1, so op0 goes first. */
return -1;
}
}
/* They are, as far as we can tell, identical.
Since qsort may have rearranged the table partially, there is
no way to tell which one was first in the opcode table as
written, so just say there are equal. */
return 0;
}

5
binutils/version.c Normal file
View File

@ -0,0 +1,5 @@
/*** version.c -- version number for binutils.
They all change in lockstep -- it's easier that way
*/
char *program_version = "1.10 (Cygnus BFD)";

182
ld/Makefile Executable file
View File

@ -0,0 +1,182 @@
#
# Makefile for ld version 2
#
# $Id$
#
srcdir = .
BASEDIR = ../..
INCLUDE = $(srcdir)/$(BASEDIR)/include-cygnus
INCLUDES = -I$(srcdir) -I$(INCLUDE)
DEBUG = -g
CFLAGS = $(INCLUDES) $(DEBUG)
# go directly to ld.new in case this ld isn't capable of
# linking native object on this host. It can be renamed on
# install.
PROGS = ld.new
# for self hosting
GNUTARGET=a.out-generic-big
LDEMULATION=gld
bfdlib=$(srcdir)/$(BASEDIR)/bfd/$(HOST)/libbfd.a
OBJS= ldgram.o ldlex.o ldlang.o ldmain.o ldwrite.o ldexp.o ld-lnk960.o \
ld-gld.o ld-gld960.o ld-emul.o ldversion.o ldmisc.o ldsym.o ldfile.o
HEADERS=config.h ldmain.h ldmain.h ldmisc.h ldsym.h ldlang.h ldexp.h \
ldlex.h ldwrite.h ldversion.h ld-emul.h ldfile.h ldgram.h ld.h
MANSOURCES=ld.tex
LDCSOURCES=ldlang.c ldmain.c ldwrite.c ld-lnk960.c ld-gld.c \
ld-gld960.c ld-emul.c ldversion.c ldmisc.c ldexp.c ldsym.c ldfile.c
GENERATED_SOURCES=ldgram.tab.c ldlex.c
GENERATED_HEADERS=ldgram.tab.h
LDSOURCES=$(LDCSOURCES) ldgram.y ldlex.l
#BFDSOURCES=../bfd/libbfd.c ../bfd/bfd.c ../bfd/sunos.c ../bfd/icoff.c ../bfd/b.out.c ../bfd/archive.c ../bfd/srec.c
SOURCES= $(LDSOURCES) $(BFDSOURCES)
LINTSOURCES= $(LDCSOURCES) $(BFDSOURCES) $(GENERATED_SOURCES)
all: $(PROGS)
$(PROGS): $(OBJS)
# (cd ../bfd; make)
# LDEMULATION=gld; export LDEMULATION; GNUTARGET=a.out-generic-big;./ldok -format a.out-generic-big -o ld /lib/crt0.o $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib
# gld -o ld /lib/crt0.o $(OBJS) $(bfdlib) -lc /usr/local/lib/gcc/sparc/1.91/gnulib
$(CC) -Bstatic -o ld.new $(OBJS) $(bfdlib)
ld1: ld
gcc -v -B./ -o ld1 $(OBJS) $(bfdlib)
ld2: ld1
mv ld1 ld
gcc -v -B./ -o ld2 $(OBJS) $(bfdlib)
ld3: ld2
mv ld2 ld
gcc -v -B./ -o ld3 $(OBJS) $(bfdlib)
ld.dvi:ld.tex
tex ld.tex
ldgram.o:ldgram.y
yacc -d ldgram.y
mv y.tab.c ldgram.tab.c
$(CC) -c $(CFLAGS) ldgram.tab.c
mv ldgram.tab.o ldgram.o
ldgram.tab.h:ldgram.o
cp y.tab.h ldgram.tab.h
ldlex.c: ldlex.l ldgram.tab.h
ldlex.o: ldlex.c ldgram.tab.h
ldmain.o: ldmain.c
ldversion.o: ldversion.c
ldfile.o: ldfile.c
ldwrite.o: ldwrite.c
ldlang.o: ldlang.c ldgram.tab.h
ld-gld.o: ld-gld.c
ld-gld960.o: ld-gld960.c
ld-emul.o:ld-emul.c
ld-lnk960.o:ld-lnk960.c
ldexp.o:ldexp.c ldgram.tab.h
ldmisc.o:ldmisc.c
ldsym.o:ldsym.c
clean:
- rm -f $(OBJS) $(GENERATED_SOURCES) $(GENERATED_HEADERS)
- rm -f ld ld1 ld2
lintlog:$(SOURCES) Makefile
$(LINT) -abhxzn $(CFLAGS) $(LINTSOURCES) \
| grep -v "pointer casts may be troublesome" \
| grep -v "possible pointer alignment problem" \
| grep -v "ignore" \
| grep -v "conversion from long may lose accuracy" \
| grep -v "warning: constant argument to NOT" \
| grep -v "enumeration type clash, operator CAST" \
| grep -v "warning: constant in conditional context"\
| grep -v "archive\.c"
tags TAGS:$(SOURCES) $(HEADERS)
etags -t $(SOURCES) $(HEADERS)
release:
(cd /4/steve/ld; tar cf - $(LDSOURCES) $(HEADERS) $(MANSOURCES)) | tar xf -
objdump:objdump.c
install: $(PROGS)
rm -f $G960BASE/bin/$(PROGS)
cp $(PROGS) $$G960BASE/bin/gld960c
#-----------------------------------------------------------------------------
# 'STANDARD' GNU/960 TARGETS BELOW THIS POINT
#
# 'VERSION' file must be present and contain a string of the form "x.y"
#-----------------------------------------------------------------------------
ver960.c: FORCE
rm -f ver960.c
echo "char ${TARG}_ver[]= \"${TARG} `cat VERSION`, `date`\";" > ver960.c
# This target should be invoked before building a new release.
# 'VERSION' file must be present and contain a string of the form "x.y"
#
roll:
@V=`cat VERSION` ; \
MAJ=`sed 's/\..*//' VERSION` ; \
MIN=`sed 's/.*\.//' VERSION` ; \
V=$$MAJ.`expr $$MIN + 1` ; \
rm -f VERSION ; \
echo $$V >VERSION ; \
echo Version $$V
# Dummy target to force execution of dependent targets.
#
.force:
FORCE:
# Target to uncomment host-specific lines in this makefile. Such lines must
# have the following string beginning in column 1: #__<hostname>__#
# Original Makefile is backed up as 'Makefile.old'.
#
# Invoke with: make make HOST=xxx
#
make:
-@if test $(HOST)x = x ; then \
echo 'Specify "make make HOST=???"'; \
exit 1; \
fi ; \
grep -s "^#The next line was generated by 'make make'" Makefile; \
if test $$? = 0 ; then \
echo "Makefile has already been processed with 'make make'";\
exit 1; \
fi ; \
mv -f Makefile Makefile.old; \
echo "#The next line was generated by 'make make'" >Makefile ; \
echo "HOST=$(HOST)" >>Makefile ; \
echo >>Makefile ; \
sed "s/^#__$(HOST)__#//" < Makefile.old >>Makefile
#
Makefile: ../common/Makefile
mv Makefile Makefile.backup
cp ../common/Makefile .
$(MAKE) "HOST=$(HOST)" make
### Local Variables: ***
### mode:fundamental ***
### page-delimiter: "^# " ***
### End: ***
### end of file

144
ld/ld-emul.c Executable file
View File

@ -0,0 +1,144 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:28:19 gumby
Initial revision
* Revision 1.1 1991/03/13 00:48:09 chrisb
* Initial revision
*
* Revision 1.4 1991/03/10 09:31:16 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.3 1991/02/22 17:14:55 sac
* Added RCS keywords and copyrights
*
*/
/*
* clearing house for ld emulation states
*/
#include "sysdep.h"
#include "bfd.h"
#include "config.h"
#include "ld.h"
#include "ld-emul.h"
#include "ldmisc.h"
extern ld_emulation_xfer_type ld_lnk960_emulation;
extern ld_emulation_xfer_type ld_gld_emulation;
extern ld_emulation_xfer_type ld_gld960_emulation;
ld_emulation_xfer_type *ld_emulation;
void
ldemul_hll(name)
char *name;
{
ld_emulation->hll(name);
}
void ldemul_syslib(name)
char *name;
{
ld_emulation->syslib(name);
}
void
ldemul_after_parse()
{
ld_emulation->after_parse();
}
void
ldemul_before_parse()
{
ld_emulation->before_parse();
}
void
ldemul_after_allocation()
{
ld_emulation->after_allocation();
}
void
ldemul_before_allocation()
{
if (ld_emulation->before_allocation) {
ld_emulation->before_allocation();
}
}
void
ldemul_set_output_arch()
{
ld_emulation->set_output_arch();
}
char *
ldemul_choose_target()
{
return ld_emulation->choose_target();
}
char *
ldemul_get_script()
{
return ld_emulation->get_script();
}
void
ldemul_choose_mode(target)
char *target;
{
if (strcmp(target,LNK960_EMULATION_NAME)==0) {
ld_emulation = &ld_lnk960_emulation;
}
else if (strcmp(target,GLD_EMULATION_NAME)==0) {
ld_emulation = &ld_gld_emulation;
}
else if (strcmp(target,GLD960_EMULATION_NAME)==0) {
ld_emulation = &ld_gld960_emulation;
}
else {
info("%P%F unrecognised emulation mode: %s",target);
}
}

258
ld/ld-gld.c Executable file
View File

@ -0,0 +1,258 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:24 gumby
* Initial revision
*
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:11 chrisb
* Initial revision
*
* Revision 1.7 1991/03/10 09:31:18 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.6 1991/03/09 03:23:12 sac
* Added -Ur loader script.
*
* Revision 1.5 1991/03/06 21:59:29 sac
* Completed G++ support
*
* Revision 1.4 1991/03/06 02:23:34 sac
* Added support for partial linking.
*
* Revision 1.3 1991/02/22 17:14:56 sac
* Added RCS keywords and copyrights
*
*/
/*
* emulate the original gld
*
* Written by Steve Chamberlain steve@cygnus.com
*/
#include "sysdep.h"
#include "bfd.h"
#include "ld.h"
#include "config.h"
#include "ld-emul.h"
#include "ldfile.h"
#include "ldmisc.h"
extern boolean lang_float_flag;
extern enum bfd_architecture ldfile_output_architecture;
extern unsigned long ldfile_output_machine;
extern char *ldfile_output_machine_name;
extern bfd *output_bfd;
static void gld_before_parse()
{
ldfile_add_library_path("/lib");
ldfile_add_library_path("/usr/lib");
ldfile_add_library_path("/usr/local/lib/lib");
ldfile_output_architecture = bfd_arch_sparc;
}
static void
gld_after_parse()
{
}
static void
gld_after_allocation()
{
}
static void
gld_before_allocation()
{
}
static void
gld_set_output_arch()
{
/* Set the output architecture and machine if possible */
unsigned long machine = 0;
bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine);
}
static char *
gld_choose_target()
{
char *from_outside = getenv(TARGET_ENVIRON);
if (from_outside != (char *)NULL)
return from_outside;
return GLD_TARGET;
}
static void
gld_syslib()
{
info("%S SYSLIB ignored\n");
}
static void
gld_hll(ignore)
char *ignore;
{
info("%S HLL ignored\n");
}
static char *gld_script = " \
SEARCH_DIR(/lib) \
SEARCH_DIR(/usr/lib) \
SEARCH_DIR(/usr/local/lib) \
__DYNAMIC = 0; \
SECTIONS \
{ \
.text 0x2020 BLOCK(0x2000): \
{ \
CREATE_OBJECT_SYMBOLS \
*(.text) \
_etext = ALIGN( 0x2000); \
} \
.data ALIGN(0x2000) : \
{ \
*(.data) \
___DTOR_LIST__=. ; \
LONG((___CTOR_LIST__ - .)/4 -2) \
*(___DTOR_LIST__) \
LONG(0) \
___CTOR_LIST__=. ; \
LONG((_edata - .)/4 -2) \
*(___CTOR_LIST__) \
LONG(0) \
_edata = .; \
} \
.bss SIZEOF(.data) + ADDR(.data) : \
{ \
*(.bss) \
[COMMON] \
_end=.; \
} \
}";
static char *gld_script_option_Ur = "\
SEARCH_DIR(/lib) \
SEARCH_DIR(/usr/lib) \
SEARCH_DIR(/usr/local/lib) \
SECTIONS \
{ \
.text 0: \
{ \
CREATE_OBJECT_SYMBOLS \
*(.text) \
} \
.data SIZEOF(.text) + ADDR(.text) : \
{ \
*(.data) \
___DTOR_LIST__=. ; \
LONG((___CTOR_LIST__ - .)/4 -2) \
*(___DTOR_LIST__) \
LONG(0) \
___CTOR_LIST__=. ; \
LONG((___end_list__ - .)/4 -2) \
*(___CTOR_LIST__) \
LONG(0) \
___end_list__ = . ; \
} \
.bss SIZEOF(.data) + ADDR(.data) : \
{ \
*(.bss) \
[COMMON] \
} \
} \
";
static char *gld_script_option_r = "\
SEARCH_DIR(/lib) \
SEARCH_DIR(/usr/lib) \
SEARCH_DIR(/usr/local/lib) \
SECTIONS \
{ \
.text 0: \
{ \
CREATE_OBJECT_SYMBOLS \
*(.text) \
} \
.data SIZEOF(.text) + ADDR(.text) : \
{ \
*(.data) \
} \
.bss SIZEOF(.data) + ADDR(.data) : \
{ \
*(.bss) \
[COMMON] \
} \
} \
";
static char *gld_get_script()
{
extern ld_config_type config;
if (config.relocateable_output == true &&
config.build_constructors == true) {
return gld_script_option_Ur;
}
if (config.relocateable_output) {
return gld_script_option_r;
}
return gld_script;
}
struct ld_emulation_xfer_struct ld_gld_emulation =
{
gld_before_parse,
gld_syslib,
gld_hll,
gld_after_parse,
gld_after_allocation,
gld_set_output_arch,
gld_choose_target,
gld_before_allocation,
gld_get_script,
};

189
ld/ld-gld960.c Executable file
View File

@ -0,0 +1,189 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:28:26 gumby
Initial revision
* Revision 1.3 1991/03/16 22:27:24 rich
* fish
*
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:12 chrisb
* Initial revision
*
* Revision 1.4 1991/03/10 09:31:19 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.3 1991/02/22 17:14:57 sac
* Added RCS keywords and copyrights
*
*/
/*
* emulate the Intels port of gld
*/
#include "sysdep.h"
#include "bfd.h"
#include "ld.h"
#include "config.h"
#include "ld-emul.h"
#include "ldfile.h"
#include "ldmisc.h"
/* IMPORTS */
extern char *output_filename;
extern boolean lang_float_flag;
extern enum bfd_architecture ldfile_output_architecture;
extern unsigned long ldfile_output_machine;
extern char *ldfile_output_machine_name;
extern bfd *output_bfd;
static void gld960_before_parse()
{
char *env ;
env = getenv("G960LIB");
if (env) {
ldfile_add_library_path(env);
}
env = getenv("G960BASE");
if (env) {
ldfile_add_library_path(concat(env,"/lib",""));
}
ldfile_output_architecture = bfd_arch_i960;
}
static void
gld960_after_parse()
{
}
static void
gld960_after_allocation()
{
}
static void
gld960_before_allocation()
{
}
static void
gld960_set_output_arch()
{
/* Set the output architecture and machine if possible */
unsigned long machine = 0;
bfd_set_arch_mach(output_bfd, ldfile_output_architecture, machine);
}
static char *
gld960_choose_target()
{
char *from_outside = getenv(TARGET_ENVIRON);
output_filename = "b.out";
if (from_outside != (char *)NULL)
return from_outside;
return GLD960_TARGET;
}
static void
gld960_syslib()
{
info("%S SYSLIB ignored\n");
}
static void
gld960_hll()
{
info("%S HLL ignored\n");
}
static char *script = "\
\
SECTIONS \
{ \
.text : \
{ \
CREATE_OBJECT_SYMBOLS \
*(.text) \
_etext =.;\
} \
\
.data SIZEOF(.text) + ADDR(.text):\
{ \
\
*(.data) \
_edata = .; \
} \
.bss SIZEOF(.data) + ADDR(.data) : \
{ _bss_start = .;\
*(.bss) \
[COMMON] \
_end = . ; \
} \
} \
";
static char *
gld960_get_script()
{
return script;
}
struct ld_emulation_xfer_struct ld_gld960_emulation =
{
gld960_before_parse,
gld960_syslib,
gld960_hll,
gld960_after_parse,
gld960_after_allocation,
gld960_set_output_arch,
gld960_choose_target,
gld960_before_allocation,
gld960_get_script,
};

321
ld/ld-lnk960.c Executable file
View File

@ -0,0 +1,321 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:28:28 gumby
Initial revision
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:13 chrisb
* Initial revision
*
* Revision 1.6 1991/03/10 09:31:20 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:23:47 sac
* Now looks in G960BASE if I960BASE isn't defined.
*
* Revision 1.4 1991/03/06 02:23:35 sac
* Added support for partial linking.
*
* Revision 1.3 1991/02/22 17:14:58 sac
* Added RCS keywords and copyrights
*
*/
/*
Written by Steve Chamberlain steve@cygnus.com
* intel coff loader emulation specific stuff
*/
#include "sysdep.h"
#include "bfd.h"
/*#include "archures.h"*/
#include "ld.h"
#include "config.h"
#include "ld-emul.h"
#include "ldmisc.h"
#include "ldlang.h"
#include "ldfile.h"
extern boolean lang_float_flag;
extern bfd *output_bfd;
extern enum bfd_architecture ldfile_output_architecture;
extern unsigned long ldfile_output_machine;
extern char *ldfile_output_machine_name;
typedef struct lib_list {
char *name;
struct lib_list *next;
} lib_list_type;
static lib_list_type *hll_list;
static lib_list_type **hll_list_tail = &hll_list;
static lib_list_type *syslib_list;
static lib_list_type **syslib_list_tail = &syslib_list;
static void
append(list, name)
lib_list_type ***list;
char *name;
{
lib_list_type *element =
(lib_list_type *)(ldmalloc(sizeof(lib_list_type)));
element->name = name;
element->next = (lib_list_type *)NULL;
**list = element;
*list = &element->next;
}
static boolean had_hll = false;
static boolean had_hll_name = false;
static void
lnk960_hll(name)
char *name;
{
had_hll = true;
if (name != (char *)NULL) {
had_hll_name = true;
append(&hll_list_tail, name);
}
}
static void
lnk960_syslib(name)
char *name;
{
append(&syslib_list_tail,name);
}
static void
lnk960_before_parse()
{
char *name = getenv("I960BASE");
if (name == (char *)NULL) {
name = getenv("G960BASE");
if (name == (char *)NULL) {
info("%P%F I960BASE and G960BASE not set\n");
}
}
ldfile_add_library_path(concat(name,"/lib",""));
ldfile_output_architecture = bfd_arch_i960;
ldfile_output_machine = bfd_mach_i960_core;
}
static void
add_on(list, search)
lib_list_type *list;
lang_input_file_enum_type search;
{
while (list) {
lang_add_input_file(list->name,
search,
(char *)NULL);
list = list->next;
}
}
static void lnk960_after_parse()
{
/* If there has been no arch, default to -KB */
if (ldfile_output_machine_name[0] ==0) {
ldfile_add_arch("kb");
}
/* if there has been no hll list then add our own */
if(had_hll && !had_hll_name) {
append(&hll_list_tail,"c");
if (lang_float_flag == true) {
append(&hll_list_tail,"m");
}
else {
append(&hll_list_tail,"mstub");
}
if (ldfile_output_machine == bfd_mach_i960_ka_sa ||
ldfile_output_machine == bfd_mach_i960_ca) {
{
append(&hll_list_tail,"f");
}
}
}
add_on(hll_list, lang_input_file_is_l_enum);
add_on(syslib_list, lang_input_file_is_search_file_enum);
}
static void
lnk960_before_allocation()
{
}
static void
lnk960_after_allocation()
{
lang_abs_symbol_at_end_of(".text","_etext");
lang_abs_symbol_at_end_of(".data","_edata");
lang_abs_symbol_at_end_of(".bss","_end");
}
static struct
{
unsigned long number;
char *name;
}
machine_table[] = {
bfd_mach_i960_core ,"CORE",
bfd_mach_i960_kb_sb ,"KB",
bfd_mach_i960_kb_sb ,"SB",
bfd_mach_i960_mc ,"MC",
bfd_mach_i960_xa ,"XA",
bfd_mach_i960_ca ,"CA",
bfd_mach_i960_ka_sa ,"KA",
bfd_mach_i960_ka_sa ,"SA",
bfd_mach_i960_core ,"core",
bfd_mach_i960_kb_sb ,"kb",
bfd_mach_i960_kb_sb ,"sb",
bfd_mach_i960_mc ,"mc",
bfd_mach_i960_xa ,"xa",
bfd_mach_i960_ca ,"ca",
bfd_mach_i960_ka_sa ,"ka",
bfd_mach_i960_ka_sa ,"sa",
0,(char *)NULL
};
static void
lnk960_set_output_arch()
{
/* Set the output architecture and machine if possible */
unsigned int i;
ldfile_output_machine = bfd_mach_i960_core;
for (i= 0; machine_table[i].name != (char*)NULL; i++) {
if (strcmp(ldfile_output_machine_name,machine_table[i].name)==0) {
ldfile_output_machine = machine_table[i].number;
break;
}
}
bfd_set_arch_mach(output_bfd, ldfile_output_architecture, ldfile_output_machine);
}
static char *
lnk960_choose_target()
{
char *from_outside = getenv(TARGET_ENVIRON);
if (from_outside != (char *)NULL)
return from_outside;
return LNK960_TARGET;
}
/* The default script if none is offered */
static char *lnk960_script = "\
SECTIONS \
{ \
.text : \
{ \
*(.text) \
} \
_etext = .;\
.data SIZEOF(.text) + ADDR(.text):\
{ \
*(.data) \
} \
_edata = .; \
.bss SIZEOF(.data) + ADDR(.data) : \
{ \
_bss_start = . ;\
*(.bss) \
[COMMON] \
} \
_end = . ; \
} \
";
static char *lnk960_script_relocateable = "\
SECTIONS \
{ \
.text 0x40000000: \
{ \
*(.text) \
} \
.data 0:\
{ \
*(.data) \
} \
.bss SIZEOF(.data) + ADDR(.data) : \
{ \
*(.bss) \
[COMMON] \
} \
} \
";
static char *lnk960_get_script()
{
extern ld_config_type config;
if (config.relocateable_output) {
return lnk960_script_relocateable;
}
return lnk960_script;
}
struct ld_emulation_xfer_struct ld_lnk960_emulation =
{
lnk960_before_parse,
lnk960_syslib,
lnk960_hll,
lnk960_after_parse,
lnk960_after_allocation,
lnk960_set_output_arch,
lnk960_choose_target,
lnk960_before_allocation,
lnk960_get_script,
};

132
ld/ld.h Normal file
View File

@ -0,0 +1,132 @@
/* ld.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define flag_is_not_at_end(x) ((x) & BSF_NOT_AT_END)
#define flag_is_ordinary_local(x) (((x) & (BSF_LOCAL))&!((x) & (BSF_DEBUGGING)))
#define flag_is_debugger(x) ((x) & BSF_DEBUGGING)
#define flag_is_undefined_or_global(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL))
#define flag_is_defined(x) (!((x) & (BSF_UNDEFINED)))
#define flag_is_global_or_common(x) ((x) & (BSF_GLOBAL | BSF_FORT_COMM))
#define flag_is_undefined_or_global_or_common(x) ((x) & (BSF_UNDEFINED | BSF_GLOBAL | BSF_FORT_COMM))
#define flag_is_common(x) ((x) & BSF_FORT_COMM)
#define flag_is_global(x) ((x) & (BSF_GLOBAL))
#define flag_is_undefined(x) ((x) & BSF_UNDEFINED)
#define flag_set(x,y) (x = y)
#define flag_is_fort_comm(x) ((x) & BSF_FORT_COMM)
#define flag_is_absolute(x) ((x) & BSF_ABSOLUTE)
/* Extra information we hold on sections */
typedef struct user_section_struct {
/* Pointer to the section where this data will go */
struct lang_input_statement_struct *file;
} section_userdata_type;
#define get_userdata(x) ((x)->userdata)
#define as_output_section_statement(x) ((x)->otheruserdata)
#if 0
/*
* Structure for communication between do_file_warnings and it's
* helper routines. Will in practice be an array of three of these:
* 0) Current line, 1) Next line, 2) Source file info.
*/
struct line_debug_entry
{
int line;
char *filename;
struct nlist *sym;
};
#endif
/* Which symbols should be stripped (omitted from the output):
none, all, or debugger symbols. */
enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols;
/* Which local symbols should be omitted:
none, all, or those starting with L.
This is irrelevant if STRIP_NONE. */
enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals;
#define ALIGN(this, boundary) ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
#if 0
#define FOREACHGLOBALSYMBOL(x) ldsym_type *x; for (x = symbol_head; x; x=x->next)
#define SECTIONLOOP(abfd, ptr) \
asection *ptr; for(ptr = abfd->sections; ptr;ptr=ptr->next)
#endif
typedef struct {
/* 1 => assign space to common symbols even if `relocatable_output'. */
boolean force_common_definition;
} args_type;
typedef int token_code_type;
typedef struct
{
unsigned int specified_data_size;
boolean magic_demand_paged;
boolean make_executable;
/* 1 => write relocation into output file so can re-input it later. */
boolean relocateable_output;
/* Will we build contstructors, or leave alone ? */
boolean build_constructors;
/* 1 => write relocation such that a UNIX linker can understand it.
This is used mainly to finish of sets that were built. */
boolean unix_relocate;
} ld_config_type;
#define set_asymbol_chain(x,y) ((x)->udata = (void *)y)
#define get_asymbol_chain(x) ((asymbol **)((x)->udata))
#define get_loader_symbol(x) ((loader_global_asymbol *)((x)->udata))
#define set_loader_symbol(x,y) ((x)->udata = (void *)y)
typedef enum {
lang_first_phase_enum,
lang_allocating_phase_enum,
lang_final_phase_enum } lang_phase_type;

770
ld/ldexp.c Normal file
View File

@ -0,0 +1,770 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:28:34 gumby
Initial revision
* Revision 1.1 1991/03/13 00:48:16 chrisb
* Initial revision
*
* Revision 1.6 1991/03/10 09:31:22 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:25:04 sac
* Added support for LONG, SHORT and BYTE keywords in scripts
*
* Revision 1.4 1991/03/06 02:27:15 sac
* Added LONG, SHORT and BYTE keywords
*
* Revision 1.3 1991/02/22 17:14:59 sac
* Added RCS keywords and copyrights
*
*/
/*
* Written by Steve Chamberlain
* steve@cygnus.com
*
* This module handles expression trees.
*/
#include "sysdep.h"
#include "bfd.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldexp.h"
#include "ldgram.tab.h"
#include "ldsym.h"
#include "ldlang.h"
extern char *output_filename;
extern unsigned int undefined_global_sym_count;
extern unsigned int defined_global_sym_count;
extern bfd *output_bfd;
extern size_t largest_section;
extern lang_statement_list_type file_chain;
extern args_type command_line;
extern ld_config_type config;
extern lang_input_statement_type *script_file;
extern unsigned int defined_global_sym_count;
extern bfd_vma print_dot;
static void
exp_print_token(outfile, code)
FILE *outfile;
token_code_type code;
{
static struct {
token_code_type code;
char *name;
} table[] =
{
INT, "int",
CHAR,"char",
NAME,"NAME",
PLUSEQ,"+=",
MINUSEQ,"-=",
MULTEQ,"*=",
DIVEQ,"/=",
LSHIFTEQ,"<<=",
RSHIFTEQ,">>=",
ANDEQ,"&=",
OREQ,"|=",
OROR,"||",
ANDAND,"&&",
EQ,"==",
NE,"!=",
LE,"<=",
GE,">=",
LSHIFT,"<<",
RSHIFT,">>=",
ALIGN_K,"ALIGN",
BLOCK,"BLOCK",
SECTIONS,"SECTIONS",
ALIGNMENT,"ALIGNMENT",
SIZEOF_HEADERS,"SIZEOF_HEADERS",
NEXT,"NEXT",
SIZEOF,"SIZEOF",
ADDR,"ADDR",
MEMORY,"MEMORY",
DSECT,"DSECT",
NOLOAD,"NOLOAD",
COPY,"COPY",
INFO,"INFO",
OVERLAY,"OVERLAY",
DEFINED,"DEFINED",
TARGET_K,"TARGET",
SEARCH_DIR,"SEARCH_DIR",
MAP,"MAP",
LONG,"LONG",
SHORT,"SHORT",
BYTE,"BYTE",
ENTRY,"ENTRY",
0,(char *)NULL} ;
unsigned int idx;
for (idx = 0; table[idx].name != (char*)NULL; idx++) {
if (table[idx].code == code) {
fprintf(outfile, "%s", table[idx].name);
return;
}
}
/* Not in table, just print it alone */
fprintf(outfile, "%c",code);
}
static void
make_abs(ptr)
etree_value_type *ptr;
{
if (ptr->section != (lang_output_section_statement_type *)NULL) {
asection *s = ptr->section->bfd_section;
ptr->value += s->vma;
ptr->section = (lang_output_section_statement_type *)NULL;
}
}
static
etree_value_type new_abs(value)
bfd_vma value;
{
etree_value_type new;
new.valid = true;
new.section = (lang_output_section_statement_type *)NULL;
new.value = value;
return new;
}
static void check(os)
lang_output_section_statement_type *os;
{
if (os == (lang_output_section_statement_type *)NULL) {
info("%F%P undefined section");
}
if (os->processed == false) {
info("%F%P forward reference of section");
}
}
etree_type *exp_intop(value)
bfd_vma value;
{
etree_type *new = (etree_type *)ldmalloc(sizeof(new->value));
new->type.node_code = INT;
new->value.value = value;
new->type.node_class = etree_value;
return new;
}
static
etree_value_type new_rel(value, section)
bfd_vma value;
lang_output_section_statement_type *section;
{
etree_value_type new;
new.valid = true;
new.value = value;
new.section = section;
return new;
}
static
etree_value_type new_rel_from_section(value, section)
bfd_vma value;
lang_output_section_statement_type *section;
{
etree_value_type new;
new.valid = true;
new.value = value;
new.section = section;
if (new.section != (lang_output_section_statement_type *)NULL) {
new.value -= section->bfd_section->vma;
}
return new;
}
static etree_value_type
fold_binary(tree, current_section, allocation_done, dot, dotp)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
bfd_vma dot;
bfd_vma *dotp;
{
etree_value_type result;
result = exp_fold_tree(tree->binary.lhs, current_section,
allocation_done, dot, dotp);
if (result.valid) {
etree_value_type other;
other = exp_fold_tree(tree->binary.rhs,
current_section,
allocation_done, dot,dotp) ;
if (other.valid) {
/* If values are from different sections, or this is an */
/* absolute expression, make both source args absolute */
if (result.section != other.section ||
current_section == (lang_output_section_statement_type *)NULL) {
make_abs(&result);
make_abs(&other);
}
switch (tree->type.node_code)
{
case '%':
/* Mod, both absolule*/
if (other.value == 0) {
info("%F%S % by zero\n");
}
result.value %= other.value;
break;
case '/':
if (other.value == 0) {
info("%F%S / by zero\n");
}
result.value /= other.value;
break;
#define BOP(x,y) case x : result.value = result.value y other.value;break;
BOP('+',+);
BOP('*',*);
BOP('-',-);
BOP(LSHIFT,<<);
BOP(RSHIFT,>>);
BOP(EQ,==);
BOP(NE,!=);
BOP('<',<);
BOP('>',>);
BOP(LE,<=);
BOP(GE,>=);
BOP('&',&);
BOP('^',^);
BOP('|',|);
BOP(ANDAND,&&);
BOP(OROR,||);
default:
FAIL();
}
}
}
return result;
}
etree_value_type invalid()
{
etree_value_type new;
new.valid = false;
return new;
}
etree_value_type fold_name(tree, current_section, allocation_done, dot)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
bfd_vma dot;
{
etree_value_type result;
switch (tree->type.node_code)
{
case DEFINED:
result.value =
ldsym_get_soft(tree->name.name) != (ldsym_type *)NULL;
result.section = 0;
result.valid = true;
break;
case NAME:
result.valid = false;
if (tree->name.name[0] == '.' && tree->name.name[1] == 0) {
if (allocation_done != lang_first_phase_enum) {
result = new_rel_from_section(dot, current_section);
}
else {
result = invalid();
}
}
else {
if (allocation_done == lang_final_phase_enum) {
ldsym_type *sy = ldsym_get_soft(tree->name.name);
if (sy) {
asymbol **sdefp = sy->sdefs_chain;
if (sdefp) {
asymbol *sdef = *sdefp;
if (sdef->section == (asection *)NULL) {
/* This is an absolute symbol */
result = new_abs(sdef->value);
}
else {
lang_output_section_statement_type *os =
lang_output_section_statement_lookup( sdef->section->output_section->name);
result = new_rel(sdef->value, os);
}
}
}
if (result.valid == false) {
info("%F%S: undefined symbol `%s' referenced in expression.\n",
tree->name.name);
}
}
}
break;
case ADDR:
if (allocation_done != lang_first_phase_enum) {
lang_output_section_statement_type *os =
lang_output_section_find(tree->name.name);
check(os);
result = new_rel((bfd_vma)0, os);
}
else {
result = invalid();
}
break;
case SIZEOF:
if(allocation_done != lang_first_phase_enum) {
lang_output_section_statement_type *os =
lang_output_section_find(tree->name.name);
check(os);
result = new_abs((bfd_vma)(os->bfd_section->size));
}
else {
result = invalid();
}
break;
default:
FAIL();
break;
}
return result;
}
etree_value_type exp_fold_tree(tree, current_section, allocation_done,
dot, dotp)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
bfd_vma dot;
bfd_vma *dotp;
{
etree_value_type result;
if (tree == (etree_type *)NULL) {
result.valid = false;
}
else {
switch (tree->type.node_class)
{
case etree_value:
result = new_rel(tree->value.value, current_section);
break;
case etree_unary:
result = exp_fold_tree(tree->unary.child,
current_section,
allocation_done, dot, dotp);
if (result.valid == true)
{
switch(tree->type.node_code)
{
case ALIGN_K:
if (allocation_done != lang_first_phase_enum) {
result = new_rel_from_section(ALIGN(dot,
result.value) ,
current_section);
}
else {
result.valid = false;
}
break;
case '-':
result.value = -result.value;
break;
case NEXT:
result.valid = false;
break;
default:
FAIL();
}
}
break;
case etree_trinary:
result = exp_fold_tree(tree->trinary.cond,
current_section,
allocation_done, dot, dotp);
if (result.valid) {
result = exp_fold_tree(result.value ?
tree->trinary.lhs:tree->trinary.rhs,
current_section,
allocation_done, dot, dotp);
}
break;
case etree_binary:
result = fold_binary(tree, current_section, allocation_done,
dot, dotp);
break;
case etree_assign:
if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) {
/* Assignment to dot can only be done during allocation */
if (allocation_done == lang_allocating_phase_enum) {
result = exp_fold_tree(tree->assign.src,
current_section,
lang_allocating_phase_enum, dot, dotp);
if (result.valid == false) {
info("%F%S invalid assignment to location counter\n");
}
else {
if (current_section ==
(lang_output_section_statement_type *)NULL) {
info("%F%S assignment to location counter invalid outside of SECTION\n");
}
else {
unsigned long nextdot =result.value +
current_section->bfd_section->vma;
if (nextdot < dot) {
info("%F%S cannot move location counter backwards");
}
else {
*dotp = nextdot;
}
}
}
}
}
else {
ldsym_type *sy = ldsym_get(tree->assign.dst);
/* If this symbol has just been created then we'll place it into
* a section of our choice
*/
result = exp_fold_tree(tree->assign.src,
current_section, allocation_done,
dot, dotp);
if (result.valid)
{
asymbol *def;
asymbol **def_ptr = (asymbol **)ldmalloc(sizeof(asymbol **));
/* Add this definition to script file */
def = (asymbol *)bfd_make_empty_symbol(script_file->the_bfd);
*def_ptr = def;
def->value = result.value;
if (result.section !=
(lang_output_section_statement_type *)NULL) {
if (current_section !=
(lang_output_section_statement_type *)NULL) {
def->section = result.section->bfd_section;
def->flags = BSF_GLOBAL | BSF_EXPORT;
}
else {
/* Force to absolute */
def->value += result.section->bfd_section->vma;
def->section = (asection *)NULL;
def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
}
}
else {
def->section = (asection *)NULL;
def->flags = BSF_GLOBAL | BSF_EXPORT | BSF_ABSOLUTE;
}
def->udata = (void *)NULL;
def->name = sy->name;
Q_enter_global_ref(def_ptr);
}
}
break;
case etree_name:
result = fold_name(tree, current_section, allocation_done, dot);
break;
default:
info("%F%S Need more of these %d",tree->type.node_class );
}
}
return result;
}
etree_value_type exp_fold_tree_no_dot(tree, current_section, allocation_done)
etree_type *tree;
lang_output_section_statement_type *current_section;
lang_phase_type allocation_done;
{
return exp_fold_tree(tree, current_section, allocation_done, (bfd_vma)
0, (bfd_vma *)NULL);
}
etree_type *
exp_binop(code, lhs, rhs)
int code;
etree_type *lhs;
etree_type *rhs;
{
etree_type value, *new;
etree_value_type r;
value.type.node_code = code;
value.binary.lhs = lhs;
value.binary.rhs = rhs;
value.type.node_class = etree_binary;
r = exp_fold_tree_no_dot(&value, (lang_output_section_statement_type *)NULL,
lang_first_phase_enum );
if (r.valid)
{
return exp_intop(r.value);
}
new = (etree_type *)ldmalloc(sizeof(new->binary));
memcpy((char *)new, (char *)&value, sizeof(new->binary));
return new;
}
etree_type *
exp_trinop(code, cond, lhs, rhs)
int code;
etree_type *cond;
etree_type *lhs;
etree_type *rhs;
{
etree_type value, *new;
etree_value_type r;
value.type.node_code = code;
value.trinary.lhs = lhs;
value.trinary.cond = cond;
value.trinary.rhs = rhs;
value.type.node_class = etree_trinary;
r= exp_fold_tree_no_dot(&value, (lang_output_section_statement_type
*)NULL,lang_first_phase_enum);
if (r.valid) {
return exp_intop(r.value);
}
new = (etree_type *)ldmalloc(sizeof(new->trinary));
memcpy((char *)new,(char *) &value, sizeof(new->trinary));
return new;
}
etree_type *
exp_unop(code, child)
int code;
etree_type *child;
{
etree_type value, *new;
etree_value_type r;
value.unary.type.node_code = code;
value.unary.child = child;
value.unary.type.node_class = etree_unary;
r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
lang_first_phase_enum);
if (r.valid) {
return exp_intop(r.value);
}
new = (etree_type *)ldmalloc(sizeof(new->unary));
memcpy((char *)new, (char *)&value, sizeof(new->unary));
return new;
}
etree_type *
exp_nameop(code, name)
int code;
char *name;
{
etree_type value, *new;
etree_value_type r;
value.name.type.node_code = code;
value.name.name = name;
value.name.type.node_class = etree_name;
r = exp_fold_tree_no_dot(&value,(lang_output_section_statement_type *)NULL,
lang_first_phase_enum);
if (r.valid) {
return exp_intop(r.value);
}
new = (etree_type *)ldmalloc(sizeof(new->name));
memcpy((char *)new, (char *)&value, sizeof(new->name));
return new;
}
etree_type *
exp_assop(code, dst, src)
int code;
char *dst;
etree_type *src;
{
etree_type value, *new;
value.assign.type.node_code = code;
value.assign.src = src;
value.assign.dst = dst;
value.assign.type.node_class = etree_assign;
#if 0
if (exp_fold_tree_no_dot(&value, &result)) {
return exp_intop(result);
}
#endif
new = (etree_type*)ldmalloc(sizeof(new->assign));
memcpy((char *)new, (char *)&value, sizeof(new->assign));
return new;
}
void
exp_print_tree(outfile, tree)
FILE *outfile;
etree_type *tree;
{
switch (tree->type.node_class) {
case etree_value:
fprintf(outfile,"0x%08lx",(bfd_vma)(tree->value.value));
return;
case etree_assign:
#if 0
if (tree->assign.dst->sdefs != (asymbol *)NULL){
fprintf(outfile,"%s (%x) ",tree->assign.dst->name,
tree->assign.dst->sdefs->value);
}
else {
fprintf(outfile,"%s (UNDEFINED)",tree->assign.dst->name);
}
#endif
fprintf(outfile,"%s ",tree->assign.dst);
exp_print_token(outfile,tree->type.node_code);
exp_print_tree(outfile,tree->assign.src);
break;
case etree_binary:
exp_print_tree(outfile,tree->binary.lhs);
exp_print_token(outfile,tree->type.node_code);
exp_print_tree(outfile,tree->binary.rhs);
break;
case etree_trinary:
exp_print_tree(outfile,tree->trinary.cond);
fprintf(outfile,"?");
exp_print_tree(outfile,tree->trinary.lhs);
fprintf(outfile,":");
exp_print_tree(outfile,tree->trinary.rhs);
break;
case etree_unary:
exp_print_token(outfile,tree->unary.type.node_code);
fprintf(outfile,"(");
exp_print_tree(outfile,tree->unary.child);
fprintf(outfile,")");
break;
case etree_undef:
fprintf(outfile,"????????");
break;
case etree_name:
if (tree->type.node_code == NAME) {
fprintf(outfile,"%s", tree->name.name);
}
else {
exp_print_token(outfile,tree->type.node_code);
fprintf(outfile,"(%s)", tree->name.name);
}
break;
default:
FAIL();
break;
}
}
bfd_vma
exp_get_vma(tree, def, name, allocation_done)
etree_type *tree;
bfd_vma def;
char *name;
lang_phase_type allocation_done;
{
etree_value_type r;
if (tree != (etree_type *)NULL) {
r = exp_fold_tree_no_dot(tree,
(lang_output_section_statement_type *)NULL,
allocation_done);
if (r.valid == false && name) {
info("%F%S Nonconstant expression for %s\n",name);
}
return r.value;
}
else {
return def;
}
}
int
exp_get_value_int(tree,def,name, allocation_done)
etree_type *tree;
int def;
char *name;
lang_phase_type allocation_done;
{
return (int)exp_get_vma(tree,(bfd_vma)def,name, allocation_done);
}

99
ld/ldexp.h Normal file
View File

@ -0,0 +1,99 @@
/* ldexp.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* The result of an expression tree */
typedef struct
{
bfd_vma value;
struct lang_output_section_statement_struct *section;
boolean valid;
} etree_value_type;
typedef struct
{
int node_code;
enum { etree_binary,
etree_trinary,
etree_unary,
etree_name,
etree_assign,
etree_undef,
etree_unspec,
etree_value } node_class;
} node_type;
typedef union etree_union
{
node_type type;
struct {
node_type type;
union etree_union *lhs;
union etree_union *rhs;
} binary;
struct {
node_type type;
union etree_union *cond;
union etree_union *lhs;
union etree_union *rhs;
} trinary;
struct {
node_type type;
char *dst;
union etree_union *src;
} assign;
struct {
node_type type;
union etree_union *child;
} unary;
struct {
node_type type;
char *name;
} name;
struct {
node_type type;
bfd_vma value;
} value;
} etree_type;
PROTO(etree_type *,exp_intop,(bfd_vma));
PROTO(etree_value_type, invalid,(void));
PROTO(etree_value_type, exp_fold_tree,(etree_type *, struct
lang_output_section_statement_struct *, lang_phase_type,
bfd_vma, bfd_vma *));
PROTO(etree_type *, exp_binop,(int, etree_type *, etree_type *));
PROTO(etree_type *,exp_trinop,(int,etree_type *, etree_type *, etree_type *));
PROTO(etree_type *,exp_unop,(int, etree_type *));
PROTO(etree_type *,exp_nameop,(int, char *));
PROTO(etree_type *,exp_assop,(int, char *, etree_type *));
PROTO(void, exp_print_tree,(struct _iobuf *, etree_type *));
PROTO(bfd_vma, exp_get_vma,(etree_type *, bfd_vma, char *, enum boolean));
PROTO(int, exp_get_value_int,(etree_type *, int, char *, enum boolean));

284
ld/ldfile.c Normal file
View File

@ -0,0 +1,284 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
$Id$
$Log$
Revision 1.1 1991/03/21 21:28:37 gumby
Initial revision
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:18 chrisb
* Initial revision
*
* Revision 1.4 1991/03/10 09:31:24 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.3 1991/02/22 17:15:00 sac
* Added RCS keywords and copyrights
*
*/
/*
ldfile.c
look after all the file stuff
*/
#include "sysdep.h"
#include "bfd.h"
#include "ldmisc.h"
#include "ldlang.h"
#include "ldfile.h"
#include <ctype.h>
/* EXPORT */
char *ldfile_input_filename;
char *ldfile_output_machine_name;
unsigned long ldfile_output_machine;
enum bfd_architecture ldfile_output_architecture;
boolean had_script;
/* IMPORT */
extern boolean option_v;
/* LOACL */
typedef struct search_dirs_struct
{
char *name;
struct search_dirs_struct *next;
} search_dirs_type;
static search_dirs_type *search_head;
static search_dirs_type **search_tail_ptr = &search_head;
typedef struct search_arch_struct
{
char *name;
struct search_arch_struct *next;
} search_arch_type;
static search_arch_type *search_arch_head;
static search_arch_type **search_arch_tail_ptr = &search_arch_head;
void
ldfile_add_library_path(name)
char *name;
{
search_dirs_type *new =
(search_dirs_type *)ldmalloc(sizeof(search_dirs_type));
new->name = name;
new->next = (search_dirs_type*)NULL;
*search_tail_ptr = new;
search_tail_ptr = &new->next;
}
static bfd*
cached_bfd_openr(attempt,entry)
char *attempt;
lang_input_statement_type *entry;
{
entry->the_bfd = bfd_openr(attempt, entry->target);
return entry->the_bfd;
}
static bfd *
open_a(arch, entry, lib, suffix)
char *arch;
lang_input_statement_type *entry;
char *lib;
char *suffix;
{
bfd*desc;
search_dirs_type *search ;
for (search = search_head;
search != (search_dirs_type *)NULL;
search = search->next)
{
char buffer[1000];
char *string;
if (entry->is_archive == true) {
sprintf(buffer,
"%s/%s%s%s%s",
search->name,
lib,
entry->filename, arch, suffix);
}
else {
if (entry->filename[0] == '/') {
strcpy(buffer, entry->filename);
} else {
sprintf(buffer,"%s/%s",search->name, entry->filename);
} /* */
}
string = buystring(buffer);
desc = cached_bfd_openr (string, entry);
if (desc)
{
entry->filename = string;
entry->search_dirs_flag = false;
entry->the_bfd = desc;
return desc;
}
free(string);
}
return (bfd *)NULL;
}
/* Open the input file specified by 'entry', and return a descriptor.
The open file is remembered; if the same file is opened twice in a row,
a new open is not actually done. */
void
ldfile_open_file (entry)
lang_input_statement_type *entry;
{
if (entry->superfile)
ldfile_open_file (entry->superfile);
if (entry->search_dirs_flag)
{
search_arch_type *arch;
for (arch = search_arch_head;
arch != (search_arch_type *)NULL;
arch = arch->next) {
if (open_a(arch->name,entry,"","") != (bfd *)NULL) {
return;
}
if (open_a(arch->name,entry,"lib",".a") != (bfd *)NULL) {
return;
}
}
}
else {
entry->the_bfd = cached_bfd_openr (entry->filename, entry);
}
if (!entry->the_bfd) info("%F%P: %E %I\n", entry);
}
static FILE *
try_open(name, exten)
char *name;
char *exten;
{
FILE *result;
char buff[1000];
result = fopen(name, "r");
if (result && option_v == true) {
info("%s\n",name);
return result;
}
sprintf(buff, "%s%s", name, exten);
result = fopen(buff, "r");
if (result && option_v == true) {
info("%s\n", buff);
}
return result;
}
static FILE *
find_a_name(name, extend)
char *name;
char *extend;
{
search_dirs_type *search;
FILE *result;
char buffer[1000];
/* First try raw name */
result = try_open(name,"");
if (result == (FILE *)NULL) {
/* Try now prefixes */
for (search = search_head;
search != (search_dirs_type *)NULL;
search = search->next) {
sprintf(buffer,"%s/%s", search->name, name);
result = try_open(buffer, extend);
if (result)break;
}
}
return result;
}
void ldfile_open_command_file(name)
char *name;
{
extern FILE *ldlex_input_stack;
ldlex_input_stack = find_a_name(name, ".ld");
if (ldlex_input_stack == (FILE *)NULL) {
info("%P%F cannot open load script file %s\n",name);
}
ldfile_input_filename = name;
had_script = true;
}
void
ldfile_add_arch(name)
char *name;
{
search_arch_type *new =
(search_arch_type *)ldmalloc(sizeof(search_arch_type));
ldfile_output_machine_name = name;
new->name = name;
new->next = (search_arch_type*)NULL;
while (*name) {
if (isupper(*name)) *name = tolower(*name);
name++;
}
*search_arch_tail_ptr = new;
search_arch_tail_ptr = &new->next;
}

27
ld/ldfile.h Normal file
View File

@ -0,0 +1,27 @@
/* ldfile.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
PROTO(void,ldfile_add_arch,(char *));
PROTO(void,ldfile_add_library_path,(char *));
PROTO(void,ldfile_open_command_file,(char *name));
PROTO(void,ldfile_open_file,(struct lang_input_statement_struct *));

693
ld/ldgram.y Normal file
View File

@ -0,0 +1,693 @@
%{
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:41 gumby
* Initial revision
*
* Revision 1.2 1991/03/16 22:27:24 rich
* fish
*
* Revision 1.1 1991/03/13 00:48:21 chrisb
* Initial revision
*
* Revision 1.6 1991/03/10 09:31:26 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:25:48 sac
* Can now parse the -Ur flag
*
* Revision 1.4 1991/03/06 02:26:01 sac
* Added support for constructor sections.
* Remove parsing ambiguity.
* Lint
*
* Revision 1.3 1991/02/22 17:15:13 sac
* Added RCS keywords and copyrights
*
*/
/*
This is a YACC grammer intended to parse a superset of the AT&T
linker scripting languaue.
Written by Steve Chamberlain steve@cygnus.com
*/
/*SUPPRESS 166*/
/*SUPPRESS 112*/
#include "sysdep.h"
#include "bfd.h"
#include "ld.h"
#include "ldexp.h"
#include "ldversion.h"
#include "ldlang.h"
#include "ld-emul.h"
#include "ldfile.h"
#include "ldmisc.h"
#define YYDEBUG 1
boolean option_v;
extern unsigned int lineno;
extern boolean trace_files;
extern boolean write_map;
boolean hex_mode;
lang_memory_region_type *region;
lang_memory_region_type *lang_memory_region_lookup();
lang_output_section_statement_type *lang_output_section_statement_lookup();
#ifdef __STDC__
void lang_add_data(int type, union etree_union *exp);
void lang_enter_output_section_statement(char *output_section_statement_name, etree_type *address_exp, bfd_vma block_value);
#else
void lang_add_data();
void lang_enter_output_section_statement();
#endif /* __STDC__ */
extern args_type command_line;
char *current_file;
boolean ldgram_want_filename = true;
boolean had_script = false;
boolean force_make_executable = false;
boolean ldgram_mustbe_filename = false;
boolean ldgram_mustbe_symbolname = false;
boolean ldgram_has_inputfile = false;
/* LOCALS */
%}
%union {
bfd_vma integer;
int voidval;
char *name;
int token;
union etree_union *etree;
asection *section;
struct lang_output_section_statement_struct *output_section_statement;
union lang_statement_union **statement_ptr;
int lineno;
struct {
FILE *file;
char *name;
unsigned int lineno;
} state;
}
%type <etree> exp opt_exp exp_head
%type <integer> fill_opt opt_block
%type <name> memspec_opt
%token <integer> INT CHAR
%token <name> NAME
%type <integer> length
%right <token> PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
%right <token> '?' ':'
%left <token> OROR
%left <token> ANDAND
%left <token> '|'
%left <token> '^'
%left <token> '&'
%left <token> EQ NE
%left <token> '<' '>' LE GE
%left <token> LSHIFT RSHIFT
%left <token> '+' '-'
%left <token> '*' '/' '%'
%right UNARY
%left <token> '('
%token <token> ALIGN_K BLOCK LONG SHORT BYTE
%token SECTIONS
%token '{' '}'
%token ALIGNMENT SIZEOF_HEADERS
%token NEXT SIZEOF ADDR
%token MEMORY
%token DSECT NOLOAD COPY INFO OVERLAY
%token NAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY
%token OPTION_e OPTION_c OPTION_noinhibit_exec OPTION_s OPTION_S OPTION_format
%token OPTION_d OPTION_dc OPTION_dp OPTION_x OPTION_X
%token OPTION_v OPTION_M OPTION_t STARTUP HLL SYSLIB FLOAT NOFLOAT OPTION_defsym
%token OPTION_n OPTION_r OPTION_o OPTION_b OPTION_A
%token <name> OPTION_l OPTION_L OPTION_T OPTION_Aarch OPTION_Tfile OPTION_Texp
%token OPTION_Ur
%token ORIGIN FILL OPTION_g
%token LENGTH BIND SUBSECTION_ALIGN CREATE_OBJECT_SYMBOLS INPUT OUTPUT
%type <token> assign_op SIZEOF NEXT ADDR
%type <etree> assignment
%type <name> filename
%{
ld_config_type config;
%}
%%
file: command_line { lang_final(); };
filename:
{
ldgram_mustbe_filename =true;
}
NAME
{
ldgram_mustbe_filename = false;
$$ = $2;
}
command_line:
command_line command_line_option
|
;
command_line_option:
OPTION_v
{
ldversion();
option_v = true;
}
| OPTION_t {
trace_files = true;
}
| OPTION_M {
write_map = true;
}
| OPTION_n {
config.magic_demand_paged = false;
config.make_executable = false;
}
| OPTION_s {
strip_symbols = STRIP_ALL;
}
| OPTION_S {
strip_symbols = STRIP_DEBUGGER;
}
| OPTION_r {
config.relocateable_output = true;
config.build_constructors = false;
config.magic_demand_paged = false;
}
| OPTION_Ur {
config.relocateable_output = true;
config.build_constructors = true;
config.magic_demand_paged = false;
}
| OPTION_o filename
{
lang_add_output($2);
}
| OPTION_e NAME
{ lang_add_entry($2);
}
| OPTION_X {
discard_locals = DISCARD_L;
}
| OPTION_x {
discard_locals = DISCARD_ALL;
}
| OPTION_noinhibit_exec
{
force_make_executable = true;
}
| OPTION_d {
command_line.force_common_definition = true;
}
| OPTION_dc
{
command_line.force_common_definition = true;
}
| OPTION_g
{
/* Ignored */
}
| OPTION_dp
{
command_line.force_common_definition = true;
}
| OPTION_format NAME
{
lang_add_target($2);
}
| OPTION_Texp { hex_mode =true; }
exp_head
{ lang_section_start($1, $3);
hex_mode = false; }
| OPTION_Aarch
{ ldfile_add_arch($1); }
| OPTION_b NAME
{
lang_add_target($2);
}
| OPTION_L
{
ldfile_add_library_path($1);
}
| ifile_p1
| input_list
| OPTION_c filename
{ ldfile_open_command_file($2); }
| OPTION_Tfile
{ ldfile_open_command_file($1); }
| OPTION_T filename
{ ldfile_open_command_file($2); }
| OPTION_l
{
lang_add_input_file($1,
lang_input_file_is_l_enum,
(char *)NULL);
}
| OPTION_A filename
{
lang_add_input_file($2,
lang_input_file_is_symbols_only_enum,
(char *)NULL);
}
| OPTION_defsym assignment_with_nospaces
;
input_section_spec:
NAME
{
lang_add_wild((char *)NULL, $1);
}
| '['
{
current_file = (char *)NULL;
}
file_NAME_list
']'
| NAME
{
current_file =$1;
}
'(' file_NAME_list ')'
| '*'
{
current_file = (char *)NULL;
}
'(' file_NAME_list ')'
;
file_NAME_list:
NAME
{ lang_add_wild($1, current_file); }
| file_NAME_list opt_comma NAME
{ lang_add_wild($3, current_file); }
;
ifile_p1:
memory
| sections
| startup
| high_level_library
| low_level_library
| floating_point_support
| assignment end
| TARGET_K '(' NAME ')'
{ lang_add_target($3); }
| SEARCH_DIR '(' filename ')'
{ ldfile_add_library_path($3); }
| OUTPUT '(' filename ')'
{ lang_add_output($3); }
| INPUT '(' input_list ')'
| MAP '(' filename ')'
{ lang_add_map($3); }
;
input_list:
NAME
{ lang_add_input_file($1,lang_input_file_is_file_enum,
(char *)NULL); }
| input_list ',' NAME
{ lang_add_input_file($3,lang_input_file_is_file_enum,
(char *)NULL); }
| input_list NAME
{ lang_add_input_file($2, lang_input_file_is_file_enum,
(char *)NULL); }
;
sections:
SECTIONS '{'sec_or_group_p1 '}'
;
sec_or_group_p1:
sec_or_group_p1 section
| sec_or_group_p1 statement_anywhere
|
;
statement_anywhere:
ENTRY '(' NAME ')'
{ lang_add_entry($3); }
| assignment end
;
statement:
statement assignment end
| statement CREATE_OBJECT_SYMBOLS
{ lang_add_attribute(lang_object_symbols_statement_enum); }
| statement input_section_spec
| statement length '(' exp_head ')'
{
lang_add_data($2,$4);
}
| statement FILL '(' exp_head ')'
{
lang_add_fill
(exp_get_value_int($4,
0,
"fill value",
lang_first_phase_enum));
}
|
;
length:
LONG
{ $$ = $1; }
| SHORT
{ $$ = $1; }
| BYTE
{ $$ = $1; }
;
fill_opt:
'=' exp_head
{
$$ = exp_get_value_int($2,
0,
"fill value",
lang_first_phase_enum);
}
| { $$ = 0; }
;
assign_op:
PLUSEQ
{ $$ = '+'; }
| MINUSEQ
{ $$ = '-'; }
| MULTEQ
{ $$ = '*'; }
| DIVEQ
{ $$ = '/'; }
| LSHIFTEQ
{ $$ = LSHIFT; }
| RSHIFTEQ
{ $$ = RSHIFT; }
| ANDEQ
{ $$ = '&'; }
| OREQ
{ $$ = '|'; }
;
end: ';' | ','
;
assignment_with_nospaces:
{ ldgram_want_filename = false; }
assignment
{ ldgram_want_filename = true; }
;
assignment:
NAME '=' exp_head
{
lang_add_assignment(exp_assop($2,$1,$3));
}
| NAME assign_op exp_head
{
lang_add_assignment(exp_assop('=',$1,exp_binop($2,exp_nameop(NAME,$1),$3)));
}
;
opt_comma:
',' | ;
memory:
MEMORY '{' memory_spec memory_spec_list '}'
;
memory_spec_list:
memory_spec_list memory_spec
| memory_spec_list ',' memory_spec
|
;
memory_spec:
NAME
{ region = lang_memory_region_lookup($1); }
attributes_opt ':' origin_spec opt_comma length_spec
{
}
;
origin_spec:
ORIGIN '=' exp
{ region->current =
region->origin =
exp_get_vma($3, 0L,"origin", lang_first_phase_enum); }
;
length_spec:
LENGTH '=' exp
{ region->length = exp_get_vma($3,
~((bfd_vma)0),
"length",
lang_first_phase_enum);
}
attributes_opt:
'(' NAME ')'
{
lang_set_flags(&region->flags, $2);
}
|
;
startup:
STARTUP '(' filename ')'
{ lang_startup($3); }
;
high_level_library:
HLL '(' high_level_library_NAME_list ')'
| HLL '(' ')'
{ ldemul_hll((char *)NULL); }
;
high_level_library_NAME_list:
high_level_library_NAME_list opt_comma filename
{ ldemul_hll($3); }
| filename
{ ldemul_hll($1); }
;
low_level_library:
SYSLIB '(' low_level_library_NAME_list ')'
;
low_level_library_NAME_list:
low_level_library_NAME_list opt_comma filename
{ ldemul_syslib($3); }
|
;
floating_point_support:
FLOAT
{ lang_float(true); }
| NOFLOAT
{ lang_float(false); }
;
exp :
'-' exp %prec UNARY
{ $$ = exp_unop('-', $2); }
| '(' exp ')'
{ $$ = $2; }
| NEXT '(' exp ')' %prec UNARY
{ $$ = exp_unop($1,$3); }
| '!' exp %prec UNARY
{ $$ = exp_unop('!', $2); }
| '+' exp %prec UNARY
{ $$ = $2; }
| '~' exp %prec UNARY
{ $$ = exp_unop('~', $2);}
| exp '*' exp
{ $$ = exp_binop('*', $1, $3); }
| exp '/' exp
{ $$ = exp_binop('/', $1, $3); }
| exp '%' exp
{ $$ = exp_binop('%', $1, $3); }
| exp '+' exp
{ $$ = exp_binop('+', $1, $3); }
| exp '-' exp
{ $$ = exp_binop('-' , $1, $3); }
| exp LSHIFT exp
{ $$ = exp_binop(LSHIFT , $1, $3); }
| exp RSHIFT exp
{ $$ = exp_binop(RSHIFT , $1, $3); }
| exp EQ exp
{ $$ = exp_binop(EQ , $1, $3); }
| exp NE exp
{ $$ = exp_binop(NE , $1, $3); }
| exp LE exp
{ $$ = exp_binop(LE , $1, $3); }
| exp GE exp
{ $$ = exp_binop(GE , $1, $3); }
| exp '<' exp
{ $$ = exp_binop('<' , $1, $3); }
| exp '>' exp
{ $$ = exp_binop('>' , $1, $3); }
| exp '&' exp
{ $$ = exp_binop('&' , $1, $3); }
| exp '^' exp
{ $$ = exp_binop('^' , $1, $3); }
| exp '|' exp
{ $$ = exp_binop('|' , $1, $3); }
| exp '?' exp ':' exp
{ $$ = exp_trinop('?' , $1, $3, $5); }
| exp ANDAND exp
{ $$ = exp_binop(ANDAND , $1, $3); }
| exp OROR exp
{ $$ = exp_binop(OROR , $1, $3); }
| DEFINED '(' NAME ')'
{ $$ = exp_nameop(DEFINED, $3); }
| INT
{ $$ = exp_intop($1); }
| SIZEOF '(' NAME ')'
{ $$ = exp_nameop($1,$3); }
| ADDR '(' NAME ')'
{ $$ = exp_nameop($1,$3); }
| ALIGN_K '(' exp ')'
{ $$ = exp_unop($1,$3); }
| NAME
{ $$ = exp_nameop(NAME,$1); }
;
section: NAME opt_exp opt_block ':' opt_things'{'
{
lang_enter_output_section_statement($1,$2,$3);
}
statement '}' fill_opt memspec_opt
{
lang_leave_output_section_statement($10, $11);
}
;
opt_things:
{
}
;
exp_head:
{ ldgram_mustbe_symbolname = true; }
exp
{ ldgram_mustbe_symbolname = false;
$$ = $2;
}
opt_exp:
exp
{ $$ = $1; }
| { $$= (etree_type *)NULL; }
;
opt_block:
BLOCK '(' exp_head ')'
{ $$ = exp_get_value_int($3,
1L,
"block",
lang_first_phase_enum);
}
| { $$ = 1; }
;
memspec_opt:
'>' NAME
{ $$ = $2; }
| { $$ = "*default*"; }
;

2231
ld/ldlang.c Normal file

File diff suppressed because it is too large Load Diff

347
ld/ldlang.h Normal file
View File

@ -0,0 +1,347 @@
/* ldlang.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
typedef enum {
lang_input_file_is_l_enum,
lang_input_file_is_symbols_only_enum,
lang_input_file_is_marker_enum,
lang_input_file_is_fake_enum,
lang_input_file_is_search_file_enum,
lang_input_file_is_file_enum } lang_input_file_enum_type;
typedef unsigned short fill_type;
typedef struct statement_list {
union lang_statement_union *head;
union lang_statement_union **tail;
} lang_statement_list_type;
typedef struct {
boolean flag_read;
boolean flag_write;
boolean flag_executable;
boolean flag_loadable;
} lang_section_flags_type;
typedef struct memory_region_struct {
char *name;
struct memory_region_struct *next;
bfd_vma origin;
bfd_offset length;
bfd_vma current;
lang_section_flags_type flags;
} lang_memory_region_type ;
typedef struct lang_statement_header_struct
{
union lang_statement_union *next;
enum statement_enum {
lang_output_section_statement_enum,
lang_assignment_statement_enum,
lang_input_statement_enum,
lang_address_statement_enum,
lang_wild_statement_enum,
lang_input_section_enum,
lang_common_statement_enum,
lang_object_symbols_statement_enum,
lang_fill_statement_enum,
lang_data_statement_enum,
lang_target_statement_enum,
lang_output_statement_enum,
lang_padding_statement_enum,
lang_afile_asection_pair_statement_enum
} type;
} lang_statement_header_type;
typedef struct
{
lang_statement_header_type header;
union etree_union *exp;
} lang_assignment_statement_type;
typedef struct lang_target_statement_struct {
lang_statement_header_type header;
char *target;
} lang_target_statement_type;
typedef struct lang_output_statement_struct {
lang_statement_header_type header;
char *name;
} lang_output_statement_type;
typedef struct lang_output_section_statement_struct
{
lang_statement_header_type header;
union etree_union *addr_tree;
lang_statement_list_type children;
char *memspec;
union lang_statement_union *next;
char *name;
unsigned long subsection_alignment;
boolean processed;
asection *bfd_section;
lang_section_flags_type flags;
struct memory_region_struct *region;
size_t block_value;
fill_type fill;
} lang_output_section_statement_type;
typedef struct {
lang_statement_header_type header;
} lang_common_statement_type;
typedef struct {
lang_statement_header_type header;
} lang_object_symbols_statement_type;
typedef struct {
lang_statement_header_type header;
fill_type fill;
} lang_fill_statement_type;
typedef struct {
lang_statement_header_type header;
unsigned int type;
union etree_union *exp;
bfd_vma value;
asection *output_section;
bfd_vma output_vma;
} lang_data_statement_type;
typedef struct lang_input_statement_struct
{
lang_statement_header_type header;
/* Name of this file. */
char *filename;
/* Name to use for the symbol giving address of text start */
/* Usually the same as filename, but for a file spec'd with -l
this is the -l switch itself rather than the filename. */
char *local_sym_name;
/* Describe the layout of the contents of the file */
/* The file's a.out header. */
/* struct exec header;*/
/* Offset in file of GDB symbol segment, or 0 if there is none. */
int symseg_offset;
/* Describe data from the file loaded into core */
bfd *the_bfd;
boolean closed;
file_ptr passive_position;
/* Symbol table of the file. */
asymbol **asymbols;
unsigned int symbol_count;
/* Next two used only if `relocatable_output' or if needed for */
/* output of undefined reference line numbers. */
/* Text reloc info saved by `write_text' for `coptxtrel'. */
/* Offset in bytes in the output file symbol table
of the first local symbol for this file. Set by `write_file_symbols'. */
int local_syms_offset;
/* For library members only */
/* For a library, points to chain of entries for the library members. */
struct lang_input_statement_struct *subfiles;
/* For a library member, offset of the member within the archive.
Zero for files that are not library members. */
/* int starting_offset;*/
/* Size of contents of this file, if library member. */
int total_size;
/* For library member, points to the library's own entry. */
struct lang_input_statement_struct *superfile;
/* For library member, points to next entry for next member. */
struct lang_input_statement_struct *chain;
/* Point to the next file - whatever it is, wanders up and down archives */
union lang_statement_union *next;
/* Point to the next file, but skips archive contents */
union lang_statement_union *next_real_file;
boolean is_archive;
/* 1 if file's header has been read into this structure. */
boolean header_read_flag;
/* 1 means search a set of directories for this file. */
boolean search_dirs_flag;
/* 1 means this is base file of incremental load.
Do not load this file's text or data.
Also default text_start to after this file's bss. */
boolean just_syms_flag;
boolean loaded;
/* unsigned int globals_in_this_file;*/
char *target;
boolean real;
asection *common_section;
asection *common_output_section;
} lang_input_statement_type;
typedef struct {
lang_statement_header_type header;
asection *section;
lang_input_statement_type *ifile;
} lang_input_section_type;
typedef struct {
lang_statement_header_type header;
asection *section;
union lang_statement_union *file;
} lang_afile_asection_pair_statement_type;
typedef struct lang_wild_statement_struct {
lang_statement_header_type header;
char *section_name;
char *filename;
lang_statement_list_type children;
} lang_wild_statement_type;
typedef struct lang_address_statement_struct {
lang_statement_header_type header;
char *section_name;
union etree_union *address;
} lang_address_statement_type;
typedef struct {
lang_statement_header_type header;
bfd_vma output_offset;
size_t size;
asection *output_section;
fill_type fill;
} lang_padding_statement_type;
typedef union lang_statement_union
{
lang_statement_header_type header;
union lang_statement_union *next;
lang_wild_statement_type wild_statement;
lang_data_statement_type data_statement;
lang_address_statement_type address_statement;
lang_output_section_statement_type output_section_statement;
lang_afile_asection_pair_statement_type afile_asection_pair_statement;
lang_assignment_statement_type assignment_statement;
lang_input_statement_type input_statement;
lang_target_statement_type target_statement;
lang_output_statement_type output_statement;
lang_input_section_type input_section;
lang_common_statement_type common_statement;
lang_object_symbols_statement_type object_symbols_statement;
lang_fill_statement_type fill_statement;
lang_padding_statement_type padding_statement;
} lang_statement_union_type;
PROTO(void,lang_init,(void));
PROTO(struct memory_region_struct ,*lang_memory_region_lookup,(char *));
PROTO(struct lang_output_section_statement_struct *,lang_output_section_find,(char *));
PROTO(void ,lang_map,(struct _iobuf *));
PROTO(void,lang_set_flags,(lang_section_flags_type *, char *));
PROTO(void,lang_add_output,(char *));
PROTO(void,lang_final,(void));
PROTO(struct symbol_cache_entry *,create_symbol,(char *, unsigned int, struct sec_struct *));
PROTO(void ,lang_process,(void));
PROTO(void ,lang_section_start,(char *, union etree_union *));
PROTO(void,lang_add_entry,(char *));
PROTO(void,lang_add_target,(char *));
PROTO(void,lang_add_wild,(char *, char *));
PROTO(void,lang_add_map,(char *));
PROTO(void,lang_add_fill,(int));
PROTO(void,lang_add_assignment,(union etree_union *));
PROTO(void,lang_add_attribute,(enum statement_enum));
PROTO(void,lang_startup,(char *));
PROTO(void,lang_float,(enum boolean));
PROTO(void,lang_leave_output_section_statement,(bfd_vma, char *));
PROTO(void,lang_abs_symbol_at_end_of,(char *, char *));
PROTO(void,lang_statement_append,(struct statement_list *, union lang_statement_union *, union lang_statement_union **));
PROTO(void, lang_for_each_file,(void (*dothis)(lang_input_statement_type *)));
#define LANG_FOR_EACH_ASYMBOL(asymbol) \
#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \
extern lang_statement_list_type file_chain; \
lang_input_statement_type *statement; \
for (statement = (lang_input_statement_type *)file_chain.head;\
statement != (lang_input_statement_type *)NULL; \
statement = (lang_input_statement_type *)statement->next)\
#define LANG_FOR_EACH_INPUT_SECTION(statement, abfd, section, x) \
{ extern lang_statement_list_type file_chain; \
lang_input_statement_type *statement; \
for (statement = (lang_input_statement_type *)file_chain.head;\
statement != (lang_input_statement_type *)NULL; \
statement = (lang_input_statement_type *)statement->next)\
{ \
asection *section; \
bfd *abfd = statement->the_bfd; \
for (section = abfd->sections; \
section != (asection *)NULL; \
section = section->next) { \
x; \
} \
} \
}
#define LANG_FOR_EACH_OUTPUT_SECTION(section, x) \
{ extern bfd *output_bfd; \
asection *section; \
for (section = output_bfd->sections; \
section != (asection *)NULL; \
section = section->next) \
{ x; } \
}
PROTO(void, lang_process,(void));
PROTO(void, ldlang_add_file,(lang_input_statement_type *));
PROTO(lang_output_section_statement_type *,lang_output_section_find,());
PROTO(lang_input_statement_type *,
lang_add_input_file,(char *name,
lang_input_file_enum_type file_type,
char *target));
PROTO(lang_output_section_statement_type *,
lang_output_section_statement_lookup,(char *name));

26
ld/ldlex.h Normal file
View File

@ -0,0 +1,26 @@
/* ldlex.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
PROTO(int, lex_input, (void));
PROTO(void, lex_unput, (int));
PROTO(int ,yywrap,(void));
PROTO(void, parse_args,(int, char **));
PROTO(void, parse_line,(char*));

490
ld/ldlex.l Normal file
View File

@ -0,0 +1,490 @@
%{
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:50 gumby
* Initial revision
*
* Revision 1.3 1991/03/16 22:27:24 rich
* fish
*
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:27 chrisb
* Initial revision
*
* Revision 1.6 1991/03/10 09:31:32 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:25:49 sac
* Can now parse the -Ur flag
*
* Revision 1.4 1991/03/06 02:26:04 sac
* Added support for constructor sections.
* Remove parsing ambiguity.
* Lint
*
* Revision 1.3 1991/02/22 17:15:14 sac
* Added RCS keywords and copyrights
*
*/
/*SUPPRESS 529*/
/*SUPPRESS 26*/
/*SUPPRESS 29*/
#define LEXDEBUG
#include "sysdep.h"
#include "bfd.h"
#include <ctype.h>
#include "ldlex.h"
#include "ld.h"
#include "ldexp.h"
#include "ldgram.tab.h"
#include "ldmisc.h"
#undef input
#undef unput
#define input lex_input
#define unput lex_unput
int debug;
extern boolean ldgram_want_filename;
extern boolean ldgram_mustbe_filename;
extern boolean ldgram_mustbe_symbolname;
static char *command_line;
extern int fgetc();
extern int yyparse();
typedef struct {
char *name;
int value;
} keyword_type;
#define RTOKEN(x) { yylval.token = x; return x; }
keyword_type keywords[] =
{
"MEMORY",MEMORY,
"ORIGIN",ORIGIN,
"BLOCK",BLOCK,
"LENGTH",LENGTH,
"ALIGN",ALIGN_K,
"SUBSECTION_ALIGN",SUBSECTION_ALIGN,
"ADDR",ADDR,
"ENTRY",ENTRY,
"NEXT",NEXT,
"MAP",MAP,
"SIZEOF",SIZEOF,
"TARGET",TARGET_K,
"SEARCH_DIR",SEARCH_DIR,
"OUTPUT",OUTPUT,
"INPUT",INPUT,
"DEFINED",DEFINED,
"CREATE_OBJECT_SYMBOLS",CREATE_OBJECT_SYMBOLS,
"SECTIONS",SECTIONS,
"FILL",FILL,
"STARTUP",STARTUP,
"HLL",HLL,
"SYSLIB",SYSLIB,
"FLOAT",FLOAT,
"LONG", LONG,
"SHORT", SHORT,
"BYTE", BYTE,
"NOFLOAT",NOFLOAT,
"o",ORIGIN,
"org",ORIGIN,
"l", LENGTH,
"len", LENGTH,
0,0};
unsigned int lineno;
extern boolean hex_mode;
FILE *ldlex_input_stack;
static unsigned int have_pushback;
#define NPUSHBACK 10
int pushback[NPUSHBACK];
int thischar;
extern char *ldfile_input_filename;
int
lex_input()
{
/*
When we know that the next token must be a filename we force the
input routine to return a '#' character, which will cause the special
filname regexp to match the following chars even if they don't look
much like a filename to any sane person.
*/
if (ldgram_mustbe_filename) {
ldgram_mustbe_filename = false;
return '#';
}
if (have_pushback > 0)
{
have_pushback --;
return thischar = pushback[have_pushback];
}
if (ldlex_input_stack) {
thischar = fgetc(ldlex_input_stack);
if (thischar == EOF) {
fclose(ldlex_input_stack);
ldlex_input_stack = (FILE *)NULL;
ldfile_input_filename = (char *)NULL;
thischar = lex_input();
}
}
else if (command_line && *command_line) {
thischar = *(command_line++);
}
else thischar = 0;
if(thischar == '\t') thischar = ' ';
return thischar ;
}
void
lex_unput(c)
int c;
{
if (have_pushback > NPUSHBACK) {
info("%F%P Too many pushbacks\n");
}
pushback[have_pushback] = c;
have_pushback ++;
}
int
yywrap()
{ return 1; }
/*VARARGS*/
void
allprint(x)
int x;
{
fprintf(yyout,"%d",x);
}
void
sprint(x)
char *x;
{
fprintf(yyout,"%s",x);
}
int thischar;
void parse_line(arg)
char *arg;
{
command_line = arg;
have_pushback = 0;
yyparse();
}
void
parse_args(ac, av)
int ac;
char **av;
{
char *p;
int i;
size_t size = 0;
char *dst;
debug = 1;
for (i= 1; i < ac; i++) {
size += strlen(av[i]) + 2;
}
dst = p = (char *)ldmalloc(size + 2);
/* Put a space arount each option */
for (i =1; i < ac; i++) {
unsigned int s = strlen(av[i]);
*dst++ = ' ';
memcpy(dst, av[i], s);
dst[s] = ' ';
dst += s + 1;
}
*dst = 0;
parse_line(p);
free(p);
}
long number(text, base)
char *text;
int base;
{
unsigned long l = 0;
char *p;
for (p = text; *p != 0; p++) {
if (*p == 'K') {
l =l * 1024;
}
else if(*p== 'M') {
l =l * 1024 * 1024;
}
else {
l =l * base;
if (isdigit(*p)) {
l += *p - '0';
}
else if (islower(*p)) {
l += *p - 'a' + 10;
}
else {
l += *p - 'A' + 10;
}
}
}
return l;
}
%}
%a 4000
%o 5000
FILENAMECHAR [a-zA-Z0-9\/\.\-\_\+]
FILENAME {FILENAMECHAR}+
WHITE [ \t]+
%%
"\n" { lineno++; }
"\ -defsym" { return OPTION_defsym; }
"\ -noinhibit_exec" { return OPTION_noinhibit_exec; }
"\ -format" { return OPTION_format; }
"\ -n" { return OPTION_n; }
"\ -r" { return OPTION_r; }
"\ -Ur" { return OPTION_Ur; }
"\ -o" { return OPTION_o; }
"\ -g" { return OPTION_g; }
"\ -e" { return OPTION_e; }
"\ -b" { return OPTION_b; }
"\ -dc" { return OPTION_dc; }
"\ -dp" { return OPTION_dp; }
"\ -d" { return OPTION_d; }
"\ -v" { return OPTION_v; }
"\ -M" { return OPTION_M; }
"\ -t" { return OPTION_t; }
"\ -X" { return OPTION_X; }
"\ -x" { return OPTION_x; }
"\ -c" { return OPTION_c; }
"\ -s" { return OPTION_s; }
"\ -S" { return OPTION_S; }
"\ -l"{FILENAME} {
yylval.name = buystring(yytext+3);
return OPTION_l;
}
"\ -L"{FILENAME} {
yylval.name = buystring(yytext+3);
return OPTION_L;
}
"\ -Ttext" {
yylval.name = ".text";
return OPTION_Texp;
}
"\ -Tdata" {
yylval.name = ".data";
return OPTION_Texp;
}
"\ -Tbss" {
yylval.name = ".bss";
return OPTION_Texp;
}
"\ -T"{FILENAME} {
yylval.name = buystring(yytext+3);
return OPTION_Tfile;
}
"\ -T" {
return OPTION_T;
}
"\ -A"{FILENAME} {
yylval.name = buystring(yytext+3);
return OPTION_Aarch;
}
" " { }
"<<=" { RTOKEN(LSHIFTEQ);}
">>=" { RTOKEN(RSHIFTEQ);}
"||" { RTOKEN(OROR);}
"==" { RTOKEN(EQ);}
"!=" { RTOKEN(NE);}
">=" { RTOKEN(GE);}
"<=" { RTOKEN(LE);}
"<<" { RTOKEN(LSHIFT);}
">>" { RTOKEN(RSHIFT);}
"+=" { RTOKEN(PLUSEQ);}
"-=" { RTOKEN(MINUSEQ);}
"*=" { RTOKEN(MULTEQ);}
"/=" { RTOKEN(DIVEQ);}
"&=" { RTOKEN(ANDEQ);}
"|=" { RTOKEN(OREQ);}
"&&" { RTOKEN(ANDAND);}
">" { RTOKEN('>');}
"," { RTOKEN(',');}
"&" { RTOKEN('&');}
"|" { RTOKEN('|');}
"~" { RTOKEN('~');}
"!" { RTOKEN('!');}
"?" { RTOKEN('?');}
"*" { RTOKEN('*');}
"%" { RTOKEN('%');}
"<" { RTOKEN('<');}
"+" { RTOKEN('+');}
">" { RTOKEN('>');}
"}" { RTOKEN('}') ; }
"{" { RTOKEN('{'); }
")" { RTOKEN(')');}
"(" { RTOKEN('(');}
"]" { RTOKEN(']');}
"[" { RTOKEN('[');}
":" { RTOKEN(':'); }
";" { RTOKEN(';');}
"-" { RTOKEN('-');}
"=" { RTOKEN('=');}
"/*" {
while (1) {
int ch;
ch = input();
while (ch != '*') {
if (ch == '\n') {lineno++; }
ch = input();
}
if (input() == '/') {
break;
}
unput(yytext[yyleng-1]);
}
}
"\""[^\"]*"\"" {
yylval.name = buystring(yytext+1);
yylval.name[yyleng-2] = 0; /* Fry final quote */
return NAME;
}
[0][0-7KM]* {
yylval.integer = number(yytext+1, 8);
return INT;
}
[0-9]+[KM]? {
if (hex_mode == true) {
yylval.integer = number(yytext, 16);
}
else {
yylval.integer = number(yytext, 10);
}
return INT;
}
0[Xx][0-9a-fA-FKM]+ {
yylval.integer = number(yytext+2,16);
return INT;
}
"\#"{WHITE}*{FILENAMECHAR}+ {
char *p = yytext+1;
while(*p ==' ' || *p == '\t') p++;
yylval.name = buystring(p);
return NAME;
}
{FILENAMECHAR} {
int ch;
keyword_type *k;
if (yytext[0] == '/' && ldgram_mustbe_symbolname)
{ RTOKEN('/');}
ch = input();
while (true) {
if (isalpha(ch) || isdigit(ch) || ch == '.' || ch == '_') {
yytext[yyleng++] = ch;
}
else if (ch == '-' && ldgram_want_filename == true) {
yytext[yyleng++] = ch;
}
else if (ch == '+' && ldgram_want_filename == true) {
yytext[yyleng++] = ch;
}
else if (ch == '/' && ldgram_want_filename == true) {
yytext[yyleng++] = ch;
}
else break;
ch = input();
}
yytext[yyleng] = 0;
unput(ch);
for(k = keywords; k ->name != (char *)NULL; k++) {
if (strcmp(k->name, yytext)==0) {
yylval.token = k->value;
return k->value;
}
}
yylval.name = buystring(yytext);
return NAME;
}
%%

806
ld/ldmain.c Normal file
View File

@ -0,0 +1,806 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* Written by Steve Chamberlain steve@cygnus.com
*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:52 gumby
* Initial revision
*
* Revision 1.1 1991/03/13 00:48:27 chrisb
* Initial revision
*
* Revision 1.7 1991/03/10 19:15:45 sac
* Fixed a prototype problem
*
* Revision 1.6 1991/03/10 09:31:32 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:31:02 sac
* After a fatal info message, the output file is deleted.
*
* Revision 1.4 1991/03/06 02:28:31 sac
* Fixed partial linking and error messages.
*
* Revision 1.3 1991/02/22 17:15:02 sac
* Added RCS keywords and copyrights
*
*
*/
#include "sysdep.h"
#include "bfd.h"
#include "config.h"
#include "ld.h"
#include "ldmain.h"
#include "ldmisc.h"
#include "ldwrite.h"
#include "ldgram.h"
#include "ldsym.h"
#include "ldlang.h"
#include "ld-emul.h"
#include "ldlex.h"
#include "ldfile.h"
/* IMPORTS */
extern boolean lang_has_input_file;
/* EXPORTS */
char *default_target;
char *output_filename = "a.out";
/* Name this program was invoked by. */
char *program_name;
/* The file that we're creating */
bfd *output_bfd;
extern boolean option_v;
/* The local symbol prefix */
char lprefix = 'L';
/* Count the number of global symbols multiply defined. */
int multiple_def_count;
/* Count the number of symbols defined through common declarations.
This count is referenced in symdef_library, linear_library, and
modified by enter_global_ref.
It is incremented when a symbol is created as a common, and
decremented when the common declaration is overridden
Another way of thinking of it is that this is a count of
all ldsym_types with a ->scoms field
*/
unsigned int commons_pending;
/* Count the number of global symbols referenced and not defined.
common symbols are not included in this count.
*/
unsigned int undefined_global_sym_count;
/* Count the number of warning symbols encountered. */
int warning_count;
/* have we had a load script ? */
extern boolean had_script;
/* Nonzero means print names of input files as processed. */
boolean trace_files;
/* 1 => write load map. */
boolean write_map;
int unix_relocate;
/* Force the make_executable to be output, even if there are non-fatal
errors */
boolean force_make_executable;
/* A count of the total number of local symbols ever seen - by adding
the symbol_count field of each newly read afile.*/
unsigned int total_symbols_seen;
/* A count of the number of read files - the same as the number of elements
in file_chain
*/
unsigned int total_files_seen;
/* IMPORTS */
args_type command_line;
ld_config_type config;
int
main (argc, argv)
char **argv;
int argc;
{
char *emulation;
program_name = argv[0];
output_filename = "a.out";
emulation = getenv(EMULATION_ENVIRON);
/* Initialize the data about options. */
strip_symbols = STRIP_NONE;
trace_files = false;
discard_locals = DISCARD_NONE;
write_map = false;
config.relocateable_output = false;
unix_relocate = 0;
command_line.force_common_definition = false;
ldfile_add_arch("");
config.make_executable = true;
force_make_executable = false;
/* Initialize the cumulative counts of symbols. */
undefined_global_sym_count = 0;
warning_count = 0;
multiple_def_count = 0;
commons_pending = 0;
config.magic_demand_paged = true ;
config.make_executable = true;
if (emulation == (char *)NULL) {
emulation= DEFAULT_EMULATION;
}
ldemul_choose_mode(emulation);
default_target = ldemul_choose_target();
lang_init();
ldemul_before_parse();
lang_has_input_file = false;
parse_args(argc, argv);
if (lang_has_input_file == false) {
info("%P%F: No input files\n");
}
ldemul_after_parse();
lang_process();
/* Print error messages for any missing symbols, for any warning
symbols, and possibly multiple definitions */
/* Print a map, if requested. */
if (write_map) {
ldsym_print_symbol_table ();
lang_map(stdout);
}
if (config.relocateable_output) {
output_bfd->flags &= ~( D_PAGED);
output_bfd->flags |= EXEC_P;
ldwrite();
bfd_close(output_bfd);
}
else {
output_bfd->flags |= EXEC_P;
ldwrite();
bfd_close(output_bfd);
if (config.make_executable == false && force_make_executable == false) {
unlink(output_filename);
}
return (!config.make_executable);
}
return(0);
} /* main() */
void
Q_read_entry_symbols (desc, entry)
bfd *desc;
struct lang_input_statement_struct *entry;
{
if (entry->asymbols == (asymbol **)NULL) {
size_t table_size = get_symtab_upper_bound(desc);
entry->asymbols = (asymbol **)ldmalloc(table_size);
entry->symbol_count = bfd_canonicalize_symtab(desc, entry->asymbols) ;
}
}
/*
* turn this item into a reference
*/
static void
refize(sp, nlist_p)
ldsym_type *sp;
asymbol **nlist_p;
{
asymbol *sym = *nlist_p;
sym->value = 0;
sym->flags = BSF_UNDEFINED;
sym->section = (asection *)NULL;
sym->udata =(void *)( sp->srefs_chain);
sp->srefs_chain = nlist_p;
}
/*
This function is called for each name which is seen which has a global
scope. It enters the name into the global symbol table in the correct
symbol on the correct chain. Remember that each ldsym_type has three
chains attatched, one of all definitions of a symbol, one of all
references of a symbol and one of all common definitions of a symbol.
When the function is over, the supplied is left connected to the bfd
to which is was born, with its udata field pointing to the next member
on the chain in which it has been inserted.
A certain amount of jigery pokery is necessary since commons come
along and upset things, we only keep one item in the common chain; the
one with the biggest size seen sofar. When another common comes along
it either bumps the previous definition into the ref chain, since it
is bigger, or gets turned into a ref on the spot since the one on the
common chain is already bigger. If a real definition comes along then
the common gets bumped off anyway.
Whilst all this is going on we keep a count of the number of multiple
definitions seen, undefined global symbols and pending commons.
*/
void
Q_enter_global_ref (nlist_p)
asymbol **nlist_p;
{
asymbol *sym = *nlist_p;
char *name = sym->name;
ldsym_type *sp = ldsym_get (name);
flagword this_symbol_flags = sym->flags;
ASSERT(sym->udata == 0);
/* Just place onto correct chain */
if (flag_is_common(this_symbol_flags)) {
/* If we have a definition of this symbol already then
* this common turns into a reference. Also we only
* ever point to the largest common, so if we
* have a common, but it's bigger that the new symbol
* the turn this into a reference too.
*/
if (sp->sdefs_chain)
{
/* This is a common symbol, but we already have a definition
for it, so just link it into the ref chain as if
it were a reference
*/
refize(sp, nlist_p);
}
else if (sp->scoms_chain) {
/* If we have a previous common, keep only the biggest */
if ( (*(sp->scoms_chain))->value > sym->value) {
/* other common is bigger, throw this one away */
refize(sp, nlist_p);
}
else if (sp->scoms_chain != nlist_p) {
/* other common is smaller, throw that away */
refize(sp, sp->scoms_chain);
sp->scoms_chain = nlist_p;
}
}
else {
/* This is the first time we've seen a common, so
* remember it - if it was undefined before, we know it's defined now
*/
if (sp->srefs_chain)
undefined_global_sym_count--;
commons_pending++;
sp->scoms_chain = nlist_p;
}
}
else if (flag_is_defined(this_symbol_flags)) {
/* This is the definition of a symbol, add to def chain */
if (sp->sdefs_chain && (*(sp->sdefs_chain))->section != sym->section) {
/* Multiple definition */
asymbol *sy = *(sp->sdefs_chain);
lang_input_statement_type *stat = (lang_input_statement_type *) sy->the_bfd->usrdata;
lang_input_statement_type *stat1 = (lang_input_statement_type *) sym->the_bfd->usrdata;
asymbol ** stat1_symbols = stat1 ? stat1->asymbols: 0;
asymbol ** stat_symbols = stat ? stat->asymbols:0;
multiple_def_count++;
info("%C: multiple definition of `%T'\n",
sym->the_bfd,
sym->section,
stat1_symbols,
sym->value,
sym);
info("%C: first seen here\n",
sy->the_bfd,
sy->section,
stat_symbols,
sy->value);
}
else {
sym->udata =(void *)( sp->sdefs_chain);
sp->sdefs_chain = nlist_p;
}
/* A definition overrides a common symbol */
if (sp->scoms_chain) {
refize(sp, sp->scoms_chain);
sp->scoms_chain = 0;
commons_pending--;
}
else if (sp->srefs_chain) {
/* If previously was undefined, then remember as defined */
undefined_global_sym_count--;
}
}
else {
if (sp->scoms_chain == (asymbol **)NULL
&& sp->srefs_chain == (asymbol **)NULL
&& sp->sdefs_chain == (asymbol **)NULL) {
/* And it's the first time we've seen it */
undefined_global_sym_count++;
}
refize(sp, nlist_p);
}
ASSERT(sp->sdefs_chain == 0 || sp->scoms_chain == 0);
ASSERT(sp->scoms_chain ==0 || (*(sp->scoms_chain))->udata == 0);
}
static void
Q_enter_file_symbols (entry)
lang_input_statement_type *entry;
{
asymbol **q ;
entry->common_section =
bfd_make_section(entry->the_bfd, "COMMON");
ldlang_add_file(entry);
if (trace_files || option_v) {
info("%I\n", entry);
}
total_symbols_seen += entry->symbol_count;
total_files_seen ++;
for (q = entry->asymbols; *q; q++)
{
asymbol *p = *q;
if (flag_is_undefined_or_global_or_common(p->flags))
{
Q_enter_global_ref(q);
}
ASSERT(p->flags != 0);
}
}
/* Searching libraries */
struct lang_input_statement_struct *decode_library_subfile ();
void linear_library (), symdef_library ();
/* Search the library ENTRY, already open on descriptor DESC.
This means deciding which library members to load,
making a chain of `struct lang_input_statement_struct' for those members,
and entering their global symbols in the hash table. */
void
search_library (entry)
struct lang_input_statement_struct *entry;
{
/* No need to load a library if no undefined symbols */
if (!undefined_global_sym_count) return;
if (bfd_has_map(entry->the_bfd))
symdef_library (entry);
else
linear_library (entry);
}
void
Q_read_file_symbols (entry)
struct lang_input_statement_struct *entry;
{
if (entry->asymbols == (asymbol **)NULL
&&entry->real == true
&& entry->filename != (char *)NULL)
{
ldfile_open_file (entry);
if (bfd_check_format(entry->the_bfd, bfd_object))
{
entry->the_bfd->usrdata = (void*)entry;
Q_read_entry_symbols (entry->the_bfd, entry);
Q_enter_file_symbols (entry);
}
else if (bfd_check_format(entry->the_bfd, bfd_archive))
{
entry->the_bfd->usrdata = (void *)entry;
entry->subfiles = (lang_input_statement_type *)NULL;
search_library (entry);
}
else
{
info("%F%I: malformed input file (not rel or archive) \n", entry);
}
}
}
/* Construct and return a lang_input_statement_struct for a library member.
The library's lang_input_statement_struct is library_entry,
and the library is open on DESC.
SUBFILE_OFFSET is the byte index in the library of this member's header.
We store the length of the member into *LENGTH_LOC. */
lang_input_statement_type *
decode_library_subfile (library_entry, subfile_offset)
struct lang_input_statement_struct *library_entry;
bfd *subfile_offset;
{
register struct lang_input_statement_struct *subentry;
subentry = (struct lang_input_statement_struct *) ldmalloc (sizeof (struct lang_input_statement_struct));
subentry->filename = subfile_offset -> filename;
subentry->local_sym_name = subfile_offset->filename;
subentry->asymbols = 0;
subentry->the_bfd = subfile_offset;
subentry->subfiles = 0;
subentry->next = 0;
subentry->superfile = library_entry;
subentry->is_archive = false;
subentry->header_read_flag = false;
subentry->just_syms_flag = false;
subentry->loaded = false;
subentry->chain = 0;
return subentry;
}
boolean subfile_wanted_p ();
void
clear_syms(entry, offset)
struct lang_input_statement_struct *entry;
file_ptr offset;
{
carsym *car;
unsigned long indx = bfd_get_next_mapent(entry->the_bfd,
BFD_NO_MORE_SYMBOLS,
&car);
while (indx != BFD_NO_MORE_SYMBOLS) {
if (car->file_offset == offset) {
car->name = 0;
}
indx = bfd_get_next_mapent(entry->the_bfd, indx, &car);
}
}
/* Search a library that has a map
*/
void
symdef_library (entry)
struct lang_input_statement_struct *entry;
{
register struct lang_input_statement_struct *prev = 0;
boolean not_finished = true;
while (not_finished == true)
{
carsym *exported_library_name;
bfd *prev_archive_member_bfd = 0;
int idx = bfd_get_next_mapent(entry->the_bfd,
BFD_NO_MORE_SYMBOLS,
&exported_library_name);
not_finished = false;
while (idx != BFD_NO_MORE_SYMBOLS && undefined_global_sym_count)
{
if (exported_library_name->name)
{
ldsym_type *sp = ldsym_get_soft (exported_library_name->name);
/* If we find a symbol that appears to be needed, think carefully
about the archive member that the symbol is in. */
/* So - if it exists, and is referenced somewhere and is
undefined or */
if (sp && sp->srefs_chain && !sp->sdefs_chain)
{
bfd *archive_member_bfd = bfd_get_elt_at_index(entry->the_bfd, idx);
struct lang_input_statement_struct *archive_member_lang_input_statement_struct;
if (archive_member_bfd && bfd_check_format(archive_member_bfd, bfd_object))
{
/* Don't think carefully about any archive member
more than once in a given pass. */
if (prev_archive_member_bfd != archive_member_bfd)
{
prev_archive_member_bfd = archive_member_bfd;
/* Read the symbol table of the archive member. */
if (archive_member_bfd->usrdata != (void *)NULL) {
archive_member_lang_input_statement_struct =(lang_input_statement_type *) archive_member_bfd->usrdata;
}
else {
archive_member_lang_input_statement_struct =
decode_library_subfile (entry, archive_member_bfd);
archive_member_bfd->usrdata = (void *) archive_member_lang_input_statement_struct;
}
if (archive_member_lang_input_statement_struct == 0) {
info ("%F%I contains invalid archive member %s\n",
entry,
sp->name);
}
if (archive_member_lang_input_statement_struct->loaded == false)
{
Q_read_entry_symbols (archive_member_bfd, archive_member_lang_input_statement_struct);
/* Now scan the symbol table and decide whether to load. */
if (subfile_wanted_p (archive_member_lang_input_statement_struct) == true)
{
/* This member is needed; load it.
Since we are loading something on this pass,
we must make another pass through the symdef data. */
not_finished = true;
Q_enter_file_symbols (archive_member_lang_input_statement_struct);
if (prev)
prev->chain = archive_member_lang_input_statement_struct;
else
entry->subfiles = archive_member_lang_input_statement_struct;
prev = archive_member_lang_input_statement_struct;
/* Clear out this member's symbols from the symdef data
so that following passes won't waste time on them. */
clear_syms(entry, exported_library_name->file_offset);
archive_member_lang_input_statement_struct->loaded = true;
}
}
}
}
}
}
idx = bfd_get_next_mapent(entry->the_bfd, idx, &exported_library_name);
}
}
}
void
linear_library (entry)
struct lang_input_statement_struct *entry;
{
boolean more_to_do = true;
register struct lang_input_statement_struct *prev = 0;
while (more_to_do) {
bfd * archive = bfd_openr_next_archived_file(entry->the_bfd,0);
more_to_do = false;
while (archive) {
if (bfd_check_format(archive, bfd_object))
{
register struct lang_input_statement_struct *subentry;
subentry = decode_library_subfile (entry,
archive);
archive->usrdata = (void *) subentry;
if (!subentry) return;
if (subentry->loaded == false) {
Q_read_entry_symbols (archive, subentry);
if (subfile_wanted_p (subentry) == true)
{
Q_enter_file_symbols (subentry);
if (prev)
prev->chain = subentry;
else
entry->subfiles = subentry;
prev = subentry;
more_to_do = true;
subentry->loaded = true;
}
}
}
archive = bfd_openr_next_archived_file(entry->the_bfd,archive);
}
}
}
/* ENTRY is an entry for a library member.
Its symbols have been read into core, but not entered.
Return nonzero if we ought to load this member. */
boolean
subfile_wanted_p (entry)
struct lang_input_statement_struct *entry;
{
asymbol **q;
for (q = entry->asymbols; *q; q++)
{
asymbol *p = *q;
/* If the symbol has an interesting definition, we could
potentially want it. */
if (p->flags & BSF_FORT_COMM
|| p->flags & BSF_GLOBAL)
{
register ldsym_type *sp = ldsym_get_soft (p->name);
/* If this symbol has not been hashed,
we can't be looking for it. */
if (sp != (ldsym_type *)NULL
&& sp->sdefs_chain == (asymbol **)NULL) {
if (sp->srefs_chain != (asymbol **)NULL
|| sp->scoms_chain != (asymbol **)NULL)
{
/* This is a symbol we are looking for. It is either
not yet defined or common. */
if (flag_is_common(p->flags))
{
/* This libary member has something to
say about this element. We should
remember if its a new size */
/* Move something from the ref list to the com list */
if(sp->scoms_chain) {
/* Already a common symbol, maybe update it */
if (p->value > (*(sp->scoms_chain))->value) {
(*(sp->scoms_chain))->value = p->value;
}
}
else {
/* Take a value from the ref chain
Here we are moving a symbol from the owning bfd
to another bfd. We must set up the
common_section portion of the bfd thing */
sp->scoms_chain = sp->srefs_chain;
sp->srefs_chain =
(asymbol **)((*(sp->srefs_chain))->udata);
(*(sp->scoms_chain))->udata = (void*)NULL;
(*( sp->scoms_chain))->flags = BSF_FORT_COMM;
commons_pending++;
undefined_global_sym_count--;
} {
asymbol *com = *(sp->scoms_chain);
if (((lang_input_statement_type *)
(com->the_bfd->usrdata))->common_section ==
(asection *)NULL) {
((lang_input_statement_type *)
(com->the_bfd->usrdata))->common_section =
bfd_make_section(com->the_bfd, "COMMON");
}
}
ASSERT(p->udata == 0);
}
else {
if (write_map)
{
info("%I needed due to %s\n",entry, sp->name);
}
return true;
}
}
}
}
}
return false;
}

23
ld/ldmain.h Normal file
View File

@ -0,0 +1,23 @@
/* ldmain.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
PROTO(void, Q_enter_global_ref,(asymbol **));
PROTO(void, Q_read_file_symbols,(struct lang_input_statement_struct *));

303
ld/ldmisc.c Normal file
View File

@ -0,0 +1,303 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:55 gumby
* Initial revision
*
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:30 chrisb
* Initial revision
*
* Revision 1.7 1991/03/10 09:31:34 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.6 1991/03/09 03:31:01 sac
* After a fatal info message, the output file is deleted.
*
* Revision 1.5 1991/03/06 21:59:54 sac
* Made %C print function name if available
*
* Revision 1.4 1991/03/06 02:27:45 sac
* Added support for linenumber printing via %C
*
* Revision 1.3 1991/02/22 17:15:03 sac
* Added RCS keywords and copyrights
*
*/
/*
ldmisc.c
*/
#include "sysdep.h"
#include <varargs.h>
#include "bfd.h"
#include "ld.h"
#include "ldmisc.h"
#include "ldlang.h"
/* IMPORTS */
extern char *program_name;
extern FILE *ldlex_input_stack;
extern char *ldfile_input_filename;
extern ld_config_type config;
void
yyerror(arg)
char *arg;
{
info("%P%F: %S %s\n",arg);
}
extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];
/*
%F error is fatal
%P print progam name
%S print script file and linenumber
%E current bfd error or errno
%I filename from a lang_input_statement_type
%B filename from a bfd
%T symbol table entry
%X no object output, fail return
%V hex bfd_vma
%C Clever filename:linenumber
%
*/
void info(va_alist)
va_dcl
{
char *fmt;
boolean fatal = false;
va_list arg;
va_start(arg);
fmt = va_arg(arg, char *);
while (*fmt) {
while (*fmt != '%' && *fmt != '\0') {
fputc(*fmt, stderr);
fmt++;
}
if (*fmt == '%') {
fmt ++;
switch (*fmt++) {
case 'X':
config.make_executable = false;
break;
case 'V':
fprintf(stderr,"%08lx", va_arg(arg, bfd_vma));
break;
case 'T':
{
asymbol *symbol = va_arg(arg, asymbol *);
if (symbol) {
asection *section = symbol->section;
if ((symbol->flags & BSF_UNDEFINED) == 0) {
char *section_name = section == (asection *)NULL ?
"absolute" : section->name;
fprintf(stderr,"%s (%s)", symbol->name, section_name);
}
else {
fprintf(stderr,"%s", symbol->name);
}
}
else {
fprintf(stderr,"no symbol");
}
}
break;
case 'B':
{
bfd *abfd = va_arg(arg, bfd *);
if (abfd->my_archive) {
fprintf(stderr,"%s(%s)", abfd->my_archive->filename,
abfd->filename);
}
else {
fprintf(stderr,"%s", abfd->filename);
}
}
break;
case 'F':
fatal = true;
break;
case 'P':
fprintf(stderr,"%s", program_name);
break;
case 'E':
/* Replace with the most recent errno explanation */
fprintf(stderr, bfd_errmsg(bfd_error));
break;
case 'I':
{
lang_input_statement_type *i =
va_arg(arg,lang_input_statement_type *);
fprintf(stderr,"%s", i->local_sym_name);
}
break;
case 'S':
/* Print source script file and line number */
if (ldlex_input_stack) {
extern unsigned int lineno;
if (ldfile_input_filename == (char *)NULL) {
fprintf(stderr,"command line");
}
else {
fprintf(stderr,"%s:%u", ldfile_input_filename, lineno + 1);
}
}
else {
fprintf(stderr,"command line ");
}
break;
case 'C':
{
char *filename;
char *functionname;
unsigned int linenumber;
bfd *abfd = va_arg(arg, bfd *);
asection *section = va_arg(arg, asection *);
asymbol **symbols = va_arg(arg, asymbol **);
bfd_vma offset = va_arg(arg, bfd_vma);
if (bfd_find_nearest_line(abfd,
section,
symbols,
offset,
&filename,
&functionname,
&linenumber))
{
if (filename == (char *)NULL)
filename = abfd->filename;
if (functionname != (char *)NULL)
fprintf(stderr,"%s:%u: (%s)", filename, linenumber, functionname);
else if (linenumber != 0)
fprintf(stderr,"%s:%u", filename, linenumber);
else
fprintf(stderr,"%s", filename);
}
else {
fprintf(stderr,"%s", abfd->filename);
}
}
break;
case 's':
fprintf(stderr,"%s", va_arg(arg, char *));
break;
case 'd':
fprintf(stderr,"%d", va_arg(arg, int));
break;
default:
fprintf(stderr,"%s", va_arg(arg, char *));
break;
}
}
}
if (fatal == true) {
extern char *output_filename;
if (output_filename)
unlink(output_filename);
exit(1);
}
va_end(arg);
}
void
info_assert(file, line)
char *file;
unsigned int line;
{
info("%F%P internal error %s %d\n", file,line);
}
/* Return a newly-allocated string
whose contents concatenate those of S1, S2, S3. */
char *
concat (s1, s2, s3)
char *s1, *s2, *s3;
{
size_t len1 = strlen (s1);
size_t len2 = strlen (s2);
size_t len3 = strlen (s3);
char *result = ldmalloc (len1 + len2 + len3 + 1);
if (len1 != 0)
memcpy(result, s1, len1);
if (len2 != 0)
memcpy(result+len1, s2, len2);
if (len3 != 0)
memcpy(result+len1+len2, s2, len3);
*(result + len1 + len2 + len3) = 0;
return result;
}
char *ldmalloc (size)
size_t size;
{
char * result = malloc (size);
if (result == (char *)NULL && size != 0)
info("%F%P virtual memory exhausted\n");
return result;
}
char *buystring(x)
char *x;
{
size_t l = strlen(x)+1;
char *r = ldmalloc(l);
memcpy(r, x,l);
return r;
}

34
ld/ldmisc.h Normal file
View File

@ -0,0 +1,34 @@
/* ldmisc.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* VARARGS*/
PROTO(void,info,());
PROTO(void,info_assert,(char *, unsigned int));
PROTO(void,yyerror,(char *));
PROTO(char *,concat,(char *, char *, char *));
PROTO(char *, ldmalloc,(size_t));
PROTO(char *,buystring,(char *));
#define ASSERT(x) \
{ if (!(x)) info_assert(__FILE__,__LINE__); }
#define FAIL() \
{ info_assert(__FILE__,__LINE__); }

452
ld/ldsym.c Normal file
View File

@ -0,0 +1,452 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:28:58 gumby
* Initial revision
*
* Revision 1.1 1991/03/13 00:48:32 chrisb
* Initial revision
*
* Revision 1.4 1991/03/10 09:31:36 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.3 1991/03/06 02:28:56 sac
* Cleaned up
*
* Revision 1.2 1991/02/22 17:15:06 sac
* Added RCS keywords and copyrights
*
*/
/*
Written by Steve Chamberlain steve@cygnus.com
All symbol handling for the linker
*/
#include "sysdep.h"
#include "bfd.h"
#include "ld.h"
#include "ldsym.h"
#include "ldmisc.h"
#include "ldlang.h"
/* IMPORT */
extern bfd *output_bfd;
/* Head and tail of global symbol table chronological list */
ldsym_type *symbol_head = (ldsym_type *)NULL;
ldsym_type **symbol_tail_ptr = &symbol_head;
/*
incremented for each symbol in the ldsym_type table
no matter what flavour it is
*/
unsigned int global_symbol_count;
/* IMPORTS */
extern boolean option_longmap ;
/* LOCALS */
#define TABSIZE 1009
static ldsym_type *global_symbol_hash_table[TABSIZE];
/* Compute the hash code for symbol name KEY. */
int
hash_string (key)
char *key;
{
register char *cp;
register int k;
cp = key;
k = 0;
while (*cp)
k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
return k;
}
/* Get the symbol table entry for the global symbol named KEY.
Create one if there is none. */
ldsym_type *
ldsym_get (key)
char *key;
{
register int hashval;
register ldsym_type *bp;
/* Determine the proper bucket. */
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
if (! strcmp (key, bp->name))
return bp;
/* Nothing was found; create a new symbol table entry. */
bp = (ldsym_type *) ldmalloc (sizeof (ldsym_type));
bp->srefs_chain = (asymbol **)NULL;
bp->sdefs_chain = (asymbol **)NULL;
bp->scoms_chain = (asymbol **)NULL;
bp->name = (char *) ldmalloc (strlen (key) + 1);
strcpy (bp->name, key);
/* Add the entry to the bucket. */
bp->link = global_symbol_hash_table[hashval];
global_symbol_hash_table[hashval] = bp;
/* Keep the chronological list up to date too */
*symbol_tail_ptr = bp;
symbol_tail_ptr = &bp->next;
bp->next = 0;
global_symbol_count++;
return bp;
}
/* Like `ldsym_get' but return 0 if the symbol is not already known. */
ldsym_type *
ldsym_get_soft (key)
char *key;
{
register int hashval;
register ldsym_type *bp;
/* Determine which bucket. */
hashval = hash_string (key) % TABSIZE;
/* Search the bucket. */
for (bp = global_symbol_hash_table[hashval]; bp; bp = bp->link)
if (! strcmp (key, bp->name))
return bp;
return 0;
}
static void
list_file_locals (entry)
lang_input_statement_type *entry;
{
asymbol **q;
fprintf (stderr, "\nLocal symbols of ");
info("%I", entry);
fprintf (stderr, ":\n\n");
if (entry->asymbols) {
for (q = entry->asymbols; *q; q++)
{
asymbol *p = *q;
/* If this is a definition,
update it if necessary by this file's start address. */
if (p->flags & BSF_LOCAL)
info(" %V %s\n",p->value, p->name);
}
}
}
static void
print_file_stuff(f)
lang_input_statement_type *f;
{
fprintf (stderr, " %s", f->filename);
fprintf (stderr, " ");
if (f->just_syms_flag)
{
fprintf (stderr, " symbols only\n");
}
else
{
asection *s;
if (option_longmap) {
for (s = f->the_bfd->sections;
s != (asection *)NULL;
s = s->next) {
fprintf (stderr, "%08lx %08x 2**%2ud %s\n",
s->output_offset,
(unsigned)s->size, s->alignment_power, s->name);
}
}
else {
for (s = f->the_bfd->sections;
s != (asection *)NULL;
s = s->next) {
fprintf (stderr, "%s %lx(%x) ",
s->name,
s->output_offset,
(unsigned) s->size);
}
fprintf (stderr, "hex \n");
}
}
}
void
ldsym_print_symbol_table ()
{
fprintf (stderr, "\nFiles:\n\n");
lang_for_each_file(print_file_stuff);
fprintf (stderr, "\nGlobal symbols:\n\n");
{
register ldsym_type *sp;
for (sp = symbol_head; sp; sp = sp->next)
{
if (sp->sdefs_chain)
{
asymbol *defsym = *(sp->sdefs_chain);
asection *defsec = bfd_get_section(defsym);
fprintf(stderr,"%08lx ",defsym->value);
if (defsec)
{
fprintf(stderr,"%08lx ",defsym->value+defsec->vma);
fprintf(stderr,
"%7s",
bfd_section_name(output_bfd,
defsec));
}
else
{
fprintf(stderr," .......");
}
}
else {
fprintf(stderr,"undefined");
}
if (sp->scoms_chain) {
fprintf(stderr, " common size %5lu %s",
(*(sp->scoms_chain))->value, sp->name);
}
if (sp->sdefs_chain) {
fprintf(stderr, " symbol def %08lx %s",
(*(sp->sdefs_chain))->value,
sp->name);
}
else {
fprintf(stderr, " undefined %s",
sp->name);
}
fprintf(stderr, "\n");
}
}
lang_for_each_file(list_file_locals);
}
extern lang_output_section_statement_type *create_object_symbols;
extern char lprefix;
static asymbol **
write_file_locals(output_buffer)
asymbol **output_buffer;
{
LANG_FOR_EACH_INPUT_STATEMENT(entry)
{
/* Run trough the symbols and work out what to do with them */
unsigned int i;
/* Add one for the filename symbol if needed */
if (create_object_symbols
!= (lang_output_section_statement_type *)NULL) {
asection *s;
for (s = entry->the_bfd->sections;
s != (asection *)NULL;
s = s->next) {
if (s->output_section == create_object_symbols->bfd_section) {
/* Add symbol to this section */
asymbol * newsym =
(asymbol *)bfd_make_empty_symbol(entry->the_bfd);
newsym->name = entry->local_sym_name;
/* The symbol belongs to the output file's text section */
/* The value is the start of this section in the output file*/
newsym->value = 0;
newsym->flags = BSF_LOCAL;
newsym->section = s;
*output_buffer++ = newsym;
break;
}
}
}
for (i = 0; i < entry->symbol_count; i++)
{
asymbol *p = entry->asymbols[i];
if (flag_is_global(p->flags) || flag_is_absolute(p->flags))
{
/* We are only interested in outputting
globals at this stage in special circumstances */
if (p->the_bfd == entry->the_bfd
&& flag_is_not_at_end(p->flags)) {
/* And this is one of them */
*(output_buffer++) = p;
p->flags |= BSF_KEEP;
}
}
else {
if (flag_is_ordinary_local(p->flags))
{
if (discard_locals == DISCARD_ALL)
{ }
else if (discard_locals == DISCARD_L &&
(p->name[0] == lprefix))
{ }
else if (p->flags == BSF_WARNING)
{ }
else
{ *output_buffer++ = p; }
}
else if (flag_is_debugger(p->flags))
{
/* Only keep the debugger symbols if no stripping required */
if (strip_symbols == STRIP_NONE) {
*output_buffer++ = p;
}
}
else if (flag_is_undefined(p->flags))
{ /* This must be global */
}
else if (flag_is_common(p->flags)) {
/* And so must this */
}
else if (p->flags & BSF_CTOR) {
/* Throw it away */
}
else
{
FAIL();
}
}
}
}
return output_buffer;
}
static asymbol **
write_file_globals(symbol_table)
asymbol **symbol_table;
{
FOR_EACH_LDSYM(sp)
{
if (sp->sdefs_chain != (asymbol **)NULL) {
asymbol *bufp = (*(sp->sdefs_chain));
if ((bufp->flags & BSF_KEEP) ==0) {
ASSERT(bufp != (asymbol *)NULL);
bufp->name = sp->name;
if (sp->scoms_chain != (asymbol **)NULL)
{
/*
defined as common but not allocated, this happens
only with -r and not -d, write out a common
definition
*/
bufp = *(sp->scoms_chain);
}
*symbol_table++ = bufp;
}
}
else if (sp->scoms_chain != (asymbol **)NULL) {
/* This symbol is a common - just output */
asymbol *bufp = (*(sp->scoms_chain));
*symbol_table++ = bufp;
}
else if (sp->srefs_chain != (asymbol **)NULL) {
/* This symbol is undefined but has a reference */
asymbol *bufp = (*(sp->srefs_chain));
*symbol_table++ = bufp;
}
else {
/*
This symbol has neither defs nor refs, it must have come
from the command line, since noone has used it it has no
data attatched, so we'll ignore it
*/
}
}
return symbol_table;
}
void
ldsym_write()
{
if (strip_symbols != STRIP_ALL) {
/* We know the maximum size of the symbol table -
it's the size of all the global symbols ever seen +
the size of all the symbols from all the files +
the number of files (for the per file symbols)
+1 (for the null at the end)
*/
extern unsigned int total_files_seen;
extern unsigned int total_symbols_seen;
asymbol ** symbol_table = (asymbol **)
ldmalloc ((size_t)(global_symbol_count +
total_files_seen +
total_symbols_seen + 1) * sizeof (asymbol *));
asymbol ** tablep = write_file_locals(symbol_table);
tablep = write_file_globals(tablep);
*tablep = (asymbol *)NULL;
bfd_set_symtab(output_bfd, symbol_table, (unsigned)( tablep - symbol_table));
}
}

441
ld/ldwrite.c Normal file
View File

@ -0,0 +1,441 @@
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* $Id$
*
* $Log$
* Revision 1.1 1991/03/21 21:29:04 gumby
* Initial revision
*
* Revision 1.2 1991/03/15 18:45:55 rich
* foo
*
* Revision 1.1 1991/03/13 00:48:37 chrisb
* Initial revision
*
* Revision 1.7 1991/03/10 19:15:03 sac
* Took out the abort() which had been put in the wrong place
* Updated the version #.
*
* Revision 1.6 1991/03/10 09:31:41 rich
* Modified Files:
* Makefile config.h ld-emul.c ld-emul.h ld-gld.c ld-gld960.c
* ld-lnk960.c ld.h lddigest.c ldexp.c ldexp.h ldfile.c ldfile.h
* ldgram.y ldinfo.h ldlang.c ldlang.h ldlex.h ldlex.l ldmain.c
* ldmain.h ldmisc.c ldmisc.h ldsym.c ldsym.h ldversion.c
* ldversion.h ldwarn.h ldwrite.c ldwrite.h y.tab.h
*
* As of this round of changes, ld now builds on all hosts of (Intel960)
* interest and copy passes my copy test on big endian hosts again.
*
* Revision 1.5 1991/03/09 03:25:08 sac
* Added support for LONG, SHORT and BYTE keywords in scripts
*
* Revision 1.4 1991/03/06 21:59:34 sac
* Completed G++ support
*
* Revision 1.3 1991/03/06 02:29:52 sac
* Added support for partial linking.
*
* Revision 1.2 1991/02/22 17:15:11 sac
* Added RCS keywords and copyrights
*
*/
/*
This module writes out the final image by reading sections from the
input files, relocating them and writing them out
There are two main paths through this module, one for normal
operation and one for partial linking.
During normal operation, raw section data is read along with the
associated relocation information, the relocation info applied and
the section data written out on a section by section basis.
When partially linking, all the relocation records are read to work
out how big the output relocation vector will be. Then raw data is
read, relocated and written section by section.
Written by Steve Chamberlain steve@cygnus.com
*/
#include "sysdep.h"
#include "bfd.h"
#include "ldlang.h"
#include "ld.h"
#include "ldwrite.h"
#include "ldmisc.h"
#include "ldsym.h"
#include "ldgram.tab.h"
char *ldmalloc();
/* Static vars for do_warnings and subroutines of it */
int list_unresolved_refs; /* List unresolved refs */
int list_warning_symbols; /* List warning syms */
int list_multiple_defs; /* List multiple definitions */
extern int errno;
extern char *sys_errlist[];
extern unsigned int undefined_global_sym_count;
extern bfd *output_bfd;
extern struct lang_output_section_statement_struct * create_object_symbols;
extern char lprefix;
#ifdef __STDC__
void lang_for_each_statement(void (*func)());
#else /* __STDC__ */
void lang_for_each_statement();
#endif /* __STDC__ */
extern size_t largest_section;
ld_config_type config;
extern unsigned int global_symbol_count;
boolean trace_files;
static void perform_relocation(input_bfd,
input_section,
data,
symbols)
bfd *input_bfd;
asection *input_section;
void *data;
asymbol **symbols;
{
static asymbol *error_symbol = (asymbol *)NULL;
static unsigned int error_count = 0;
#define MAX_ERRORS_IN_A_ROW 5
size_t reloc_size = get_reloc_upper_bound(input_bfd, input_section);
arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
arelent **parent;
bfd *ob = output_bfd;
asection *os = input_section->output_section;
if (config.relocateable_output == false) ob = (bfd *)NULL;
if (bfd_canonicalize_reloc(input_bfd,
input_section,
reloc_vector,
symbols) )
{
for (parent = reloc_vector; *parent; parent++)
{
bfd_reloc_status_enum_type r=
bfd_perform_relocation(input_bfd,
*parent,
data,
input_section,
ob);
if (r == bfd_reloc_ok) {
if (ob != (bfd *)NULL) {
/* A parital link, so keep the relocs */
os->orelocation[os->reloc_count] = *parent;
os->reloc_count++;
}
}
else
{
asymbol *s;
arelent *p = *parent;
if (ob != (bfd *)NULL) {
/* A parital link, so keep the relocs */
os->orelocation[os->reloc_count] = *parent;
os->reloc_count++;
}
if (p->sym_ptr_ptr != (asymbol **)NULL) {
s = *(p->sym_ptr_ptr);
}
else {
s = (asymbol *)NULL;
}
switch (r)
{
case bfd_reloc_undefined:
/* We remember the symbol, and never print more than
a reasonable number of them in a row */
if (s == error_symbol) {
error_count++;
}
else {
error_count = 0;
error_symbol = s;
}
if (error_count < MAX_ERRORS_IN_A_ROW) {
info("%C: undefined reference to `%T'\n",
input_bfd,
input_section,
symbols,
(*parent)->address,
s);
config.make_executable = false;
}
else if (error_count == MAX_ERRORS_IN_A_ROW) {
info("%C: more undefined references to `%T' follow\n",
input_bfd,
input_section,
symbols,
(*parent)->address,
s);
}
else {
/* Don't print any more */
}
break;
case bfd_reloc_dangerous:
info("%B: relocation may be wrong `%T'\n",
input_bfd,
s);
break;
case bfd_reloc_outofrange:
info("%B:%s relocation address out of range %T (%x)\n",
input_bfd,
input_section->name,
s,
p->address);
break;
case bfd_reloc_overflow:
info("%B:%s relocation overflow in %T reloc type %d\n",
input_bfd,
input_section->name,
s,
p->howto->type);
break;
default:
info("%F%B: relocation error, symbol `%T'\n",
input_bfd,
s);
break;
}
}
}
}
free((char *)reloc_vector);
}
void *data_area;
static void
copy_and_relocate(statement)
lang_statement_union_type *statement;
{
switch (statement->header.type) {
case lang_fill_statement_enum:
{
#if 0
bfd_byte play_area[SHORT_SIZE];
unsigned int i;
bfd_putshort(output_bfd, statement->fill_statement.fill, play_area);
/* Write out all entire shorts */
for (i = 0;
i < statement->fill_statement.size - SHORT_SIZE + 1;
i+= SHORT_SIZE)
{
bfd_set_section_contents(output_bfd,
statement->fill_statement.output_section,
play_area,
statement->data_statement.output_offset +i,
SHORT_SIZE);
}
/* Now write any remaining byte */
if (i < statement->fill_statement.size)
{
bfd_set_section_contents(output_bfd,
statement->fill_statement.output_section,
play_area,
statement->data_statement.output_offset +i,
1);
}
#endif
}
break;
case lang_data_statement_enum:
{
bfd_vma value = statement->data_statement.value;
bfd_byte play_area[LONG_SIZE];
unsigned int size;
switch (statement->data_statement.type) {
case LONG:
bfd_putlong(output_bfd, value, play_area);
size = LONG_SIZE;
break;
case SHORT:
bfd_putshort(output_bfd, value, play_area);
size = SHORT_SIZE;
break;
case BYTE:
bfd_putchar(output_bfd, value, play_area);
size = BYTE_SIZE;
break;
}
bfd_set_section_contents(output_bfd,
statement->data_statement.output_section,
play_area,
statement->data_statement.output_vma,
size);
}
break;
case lang_input_section_enum:
{
asection *i = statement->input_section.section;
asection *output_section = i->output_section;
lang_input_statement_type *ifile = statement->input_section.ifile;
bfd *inbfd = ifile->the_bfd;
if (output_section->flags & SEC_LOAD && i->size != 0)
{
if(bfd_get_section_contents(inbfd,
i,
data_area,
0L,
i->size) == false)
{
info("%F%B error reading section contents %E\n",
inbfd);
}
perform_relocation (inbfd, i, data_area, ifile->asymbols);
if(bfd_set_section_contents(output_bfd,
output_section,
data_area,
(file_ptr)i->output_offset,
i->size) == false)
{
info("%F%B error writing section contents of %E\n",
output_bfd);
}
}
}
break;
default:
/* All the other ones fall through */
;
}
}
void
write_norel()
{
/* Output the text and data segments, relocating as we go. */
lang_for_each_statement(copy_and_relocate);
}
static void read_relocs(abfd, section, symbols)
bfd *abfd;
asection *section;
asymbol **symbols;
{
/* Work out the output section ascociated with this input section */
asection *output_section = section->output_section;
size_t reloc_size = get_reloc_upper_bound(abfd, section);
arelent **reloc_vector = (arelent **)ldmalloc(reloc_size);
if (bfd_canonicalize_reloc(abfd,
section,
reloc_vector,
symbols)) {
output_section->reloc_count += section->reloc_count;
}
}
static void
write_rel()
{
/*
Run through each section of each file and work work out the total
number of relocation records which will finally be in each output
section
*/
LANG_FOR_EACH_INPUT_SECTION
(statement, abfd, section,
(read_relocs(abfd, section, statement->asymbols)));
/*
Now run though all the output sections and allocate the space for
all the relocations
*/
LANG_FOR_EACH_OUTPUT_SECTION
(section,
(section->orelocation =
(arelent **)ldmalloc((size_t)(sizeof(arelent **)*
section->reloc_count)),
section->reloc_count = 0,
section->flags |= SEC_HAS_CONTENTS));
/*
Copy the data, relocating as we go
*/
lang_for_each_statement(copy_and_relocate);
}
void
ldwrite ()
{
data_area = (void*) ldmalloc(largest_section);
if (config.relocateable_output == true)
{
write_rel();
}
else
{
write_norel();
}
free(data_area);
/* Output the symbol table (both globals and locals). */
ldsym_write ();
}

24
ld/ldwrite.h Normal file
View File

@ -0,0 +1,24 @@
/* ldwrite.h -
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
GLD is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GLD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GLD; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
PROTO(void, ldwrite, (void));