Initial revision
This commit is contained in:
parent
6fd9467324
commit
2fa0b342a5
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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]);
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 (®_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;
|
||||
}
|
|
@ -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)";
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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 *));
|
||||
|
|
@ -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(®ion->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*"; }
|
||||
;
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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));
|
|
@ -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*));
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 *));
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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__); }
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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 ();
|
||||
|
||||
}
|
||||
|
|
@ -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));
|
Loading…
Reference in New Issue