281 lines
5.8 KiB
C
281 lines
5.8 KiB
C
/* ast - add symbol table. Author: Dick van Veen */
|
|
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <a.out.h>
|
|
#include <stdio.h>
|
|
|
|
/* Since the a.out file in MINIX does not contain any symbol table,
|
|
* we use the symbol table produced with the -s option of asld.
|
|
*
|
|
* Read symbol table in memory, remove compiler generated labels,
|
|
* sort the labels and add it to the a.out file.
|
|
*
|
|
* When finally there comes a real as and ld, we may also get
|
|
* a symbol table in the a.out file, and we can forget this program.
|
|
*
|
|
*/
|
|
|
|
/* Ast [flags] [file] [symbolfile]
|
|
*
|
|
* flags:
|
|
* -x do not preserve local symbols
|
|
* -X preserve local symbols except for those whose name begin
|
|
* with 'I', these are compiler generated.
|
|
*
|
|
* - when no symbol file is present, symbol.out is assumed.
|
|
* - when no file is present, a.out is assumed.
|
|
* - when one file name is present it must be the executable file
|
|
* - just one flag may be pressent.
|
|
*
|
|
*/
|
|
|
|
#define A_OUT "a.out"
|
|
#define SYMBOL_FILE "symbol.out" /* contains symbol table */
|
|
#define LINE_LENGTH 24
|
|
|
|
#define WORTH_LESS 1 /* lines contain no symbol */
|
|
#define LAST_LINE 2 /* end of file reached */
|
|
|
|
struct exec header; /* header info of a.out file */
|
|
|
|
int x_flag; /* flags to ast */
|
|
int X_flag;
|
|
int o_flag;
|
|
|
|
char *s_file, *o_file; /* names of files used by ast */
|
|
FILE *s_fd, *o_fd; /* file descriptors of those files */
|
|
int nr_symbols; /* number of symbols added */
|
|
char buffer[LINE_LENGTH]; /* contains line of symbol file */
|
|
|
|
char io_buf[BUFSIZ]; /* for buffered output on stderr */
|
|
unsigned int get_value(); /* forward definition */
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
extern FILE *fopen();
|
|
|
|
argv++;
|
|
if (*argv != NULL && **argv == '-') {
|
|
*argv += 1;
|
|
if (**argv == 'x')
|
|
x_flag = 1;
|
|
else if (**argv == 'X')
|
|
X_flag = 1;
|
|
else {
|
|
fprintf(stderr, "illegal flag: -%c\n", **argv);
|
|
exit(-1);
|
|
}
|
|
argv++;
|
|
}
|
|
if (*argv != NULL) {
|
|
o_file = *argv;
|
|
argv++;
|
|
}
|
|
if (*argv != NULL) {
|
|
s_file = *argv;
|
|
argv++;
|
|
}
|
|
if (*argv != NULL) {
|
|
fprintf(stderr, "Usage: ast [-{x,X}] [file] [symbolfile]\n");
|
|
exit(-1);
|
|
}
|
|
if (o_file == NULL) o_file = A_OUT;
|
|
o_fd = fopen(o_file, "a");
|
|
if (o_fd == NULL) {
|
|
fprintf(stderr, "can't open %s\n", o_file);
|
|
exit(-1);
|
|
}
|
|
if (s_file == NULL) s_file = SYMBOL_FILE;
|
|
s_fd = fopen(s_file, "r");
|
|
if (s_fd == NULL) {
|
|
fprintf(stderr, "can't open %s\n", s_file);
|
|
exit(-1);
|
|
}
|
|
setbuf(s_fd, io_buf);
|
|
ast(s_fd, o_fd);
|
|
exit(0);
|
|
}
|
|
|
|
ast(s_fd, o_fd)
|
|
FILE *s_fd, *o_fd;
|
|
{
|
|
struct nlist symbol;
|
|
int line_type;
|
|
|
|
do_header();
|
|
for (;;) {
|
|
read_line(s_fd, buffer);
|
|
line_type = transform_line(buffer, &symbol);
|
|
if (line_type == WORTH_LESS) continue;
|
|
if (line_type == LAST_LINE) break;
|
|
save_line(o_fd, &symbol);
|
|
}
|
|
redo_header(o_fd);
|
|
}
|
|
|
|
read_line(fd, buffer)
|
|
FILE *fd;
|
|
char *buffer;
|
|
{
|
|
int ch;
|
|
char *buf1;
|
|
|
|
buf1 = buffer;
|
|
*buffer = '\n';
|
|
ch = fgetc(fd);
|
|
while (ch != '\n' && ch != EOF) {
|
|
*buffer = ch;
|
|
buffer++;
|
|
ch = fgetc(fd);
|
|
}
|
|
if (ch == EOF)
|
|
*buffer = '\0';
|
|
else
|
|
*buffer = '\n';
|
|
buffer[1] = '\0';
|
|
}
|
|
|
|
transform_line(buffer, symbol)
|
|
char *buffer;
|
|
struct nlist *symbol;
|
|
{
|
|
switch (*buffer) {
|
|
case 'a': /* absolute symbol */
|
|
symbol->n_sclass = N_ABS;
|
|
break;
|
|
case 'A': symbol->n_sclass = N_ABS | C_EXT; break;
|
|
case 'u': /* undefined symbol */
|
|
symbol->n_sclass = N_UNDF;
|
|
break;
|
|
case 'U':
|
|
symbol->n_sclass = N_UNDF | C_EXT;
|
|
break;
|
|
|
|
case 't': /* text symbol */
|
|
symbol->n_sclass = N_TEXT;
|
|
break;
|
|
case 'T':
|
|
symbol->n_sclass = N_TEXT | C_EXT;
|
|
break;
|
|
case 'd':
|
|
symbol->n_sclass = N_DATA;
|
|
case 'D': /* data symbol */
|
|
symbol->n_sclass = N_DATA | C_EXT;
|
|
break;
|
|
case 'b':
|
|
symbol->n_sclass = N_BSS;
|
|
case 'B': /* bss symbol */
|
|
symbol->n_sclass = N_BSS | C_EXT;
|
|
break;
|
|
case '\0': /* reached end of file */
|
|
return(LAST_LINE);
|
|
default: /* one of first two lines */
|
|
return(WORTH_LESS);
|
|
}
|
|
|
|
if (buffer[1] != ' ') {
|
|
fprintf(stderr, "illegal file format\n");
|
|
exit(-1);
|
|
}
|
|
symbol->n_value = get_value(buffer + 2);
|
|
|
|
if (buffer[6] != ' ') {
|
|
fprintf(stderr, "illegal file format\n");
|
|
exit(-1);
|
|
}
|
|
get_name(buffer + 7, symbol->n_name);
|
|
return(0); /* yeah, found a symbol */
|
|
}
|
|
|
|
save_line(fd, symbol)
|
|
FILE *fd;
|
|
struct nlist *symbol;
|
|
{
|
|
if (!(symbol->n_sclass & C_EXT)) { /* local symbol */
|
|
if (x_flag) return;
|
|
if (X_flag && symbol->n_name[0] == 'I') return;
|
|
if (X_flag && symbol->n_name[0] == 'L') return;
|
|
}
|
|
if (fwrite(symbol, sizeof(struct nlist), 1, fd) != 1) {
|
|
fprintf(stderr, "can't write %s\n", o_file);
|
|
exit(-1);
|
|
}
|
|
nr_symbols++;
|
|
}
|
|
|
|
unsigned get_value(string)
|
|
char *string;
|
|
{
|
|
unsigned value;
|
|
int shift, bits;
|
|
|
|
value = 0;
|
|
for (shift = 0; shift < 16; shift += 4) {
|
|
bits = get_bits(*string);
|
|
value = (value << 4) | bits;
|
|
string++;
|
|
}
|
|
return(value);
|
|
}
|
|
|
|
get_bits(ch)
|
|
char ch;
|
|
{
|
|
if (ch >= '0' && ch <= '9') return(ch - '0');
|
|
if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 10);
|
|
if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 10);
|
|
fprintf(stderr, "illegal file format\n");
|
|
exit(-1);
|
|
}
|
|
|
|
get_name(str1, str2)
|
|
register char *str1, *str2;
|
|
{
|
|
int count;
|
|
|
|
for (count = 0; count < 8; count++) {
|
|
if (*str1 == '\n') break;
|
|
*str2++ = *str1++;
|
|
}
|
|
while (count < 8) {
|
|
*str2++ = '\0';
|
|
count++;
|
|
}
|
|
}
|
|
|
|
do_header()
|
|
{
|
|
int fd;
|
|
|
|
fd = open(o_file, O_RDONLY);
|
|
if (read(fd, &header, sizeof(struct exec)) != sizeof(struct exec)) {
|
|
fprintf(stderr, "%s: no executable file\n", o_file);
|
|
exit(-1);
|
|
}
|
|
if (BADMAG(header)) {
|
|
fprintf(stderr, "%s: bad header\n", o_file);
|
|
exit(-1);
|
|
}
|
|
if (header.a_syms != 0L) {
|
|
fprintf(stderr, "%s: symbol table is installed\n", o_file);
|
|
exit(-1);
|
|
}
|
|
fseek(o_fd, A_SYMPOS(header), 0);
|
|
nr_symbols = 0;
|
|
close(fd);
|
|
}
|
|
|
|
redo_header(fd)
|
|
FILE *fd;
|
|
{
|
|
header.a_syms = (long) (nr_symbols * sizeof(struct nlist));
|
|
fseek(fd, 0L, 0);
|
|
if (fwrite(&header, sizeof(header), 1, fd) != 1) {
|
|
fprintf(stderr, "%s: can't write\n", o_file);
|
|
exit(-1);
|
|
}
|
|
}
|