1994-06-24 11:31:16 +00:00
|
|
|
static char rcsid[] = "$Id$";
|
1987-03-11 17:12:23 +00:00
|
|
|
/*
|
|
|
|
* show - make the contents of an ACK object file human readable.
|
|
|
|
*/
|
|
|
|
|
2006-10-16 23:20:11 +00:00
|
|
|
#include <stdlib.h>
|
1987-03-11 17:12:23 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <out.h>
|
|
|
|
|
|
|
|
#define OK 0 /* Return value of gethead if Orl Korekt. */
|
|
|
|
#define BMASK 0xFF /* To extract least significant 8 bits from an int. */
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
main(argc, argv)
|
|
|
|
int argc;
|
|
|
|
char *argv[];
|
|
|
|
# define prog argv[0]
|
|
|
|
{
|
|
|
|
register char **arg = argv;
|
|
|
|
struct outhead header;
|
|
|
|
|
|
|
|
while (*++arg) {
|
|
|
|
if (! rd_open(*arg)) {
|
|
|
|
error("%s: cannot read %s\n", prog, *arg);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rd_ohead(&header);
|
|
|
|
if (BADMAGIC(header)) {
|
|
|
|
error("%s: %s not an ACK object file\n", prog, *arg);
|
|
|
|
} else {
|
|
|
|
printf("%s:\n", *arg);
|
|
|
|
show(&header);
|
|
|
|
}
|
|
|
|
rd_close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read an ACK object file from `fp' and show it in a human readable way.
|
|
|
|
* NB. The header has already been read and is in the struct outhead `headp'
|
|
|
|
* points to.
|
|
|
|
*/
|
|
|
|
show(headp)
|
|
|
|
register struct outhead *headp;
|
|
|
|
{
|
|
|
|
register int i;
|
|
|
|
register struct outname *np;
|
|
|
|
register struct outname *name; /* Dynamically allocated name-array. */
|
|
|
|
register char *string;/* Base of string area. */
|
|
|
|
extern char *myalloc();
|
|
|
|
|
|
|
|
printf("Version %d\n", headp->oh_stamp);
|
1991-12-18 09:45:26 +00:00
|
|
|
showflags((unsigned) headp->oh_flags);
|
1987-03-11 17:12:23 +00:00
|
|
|
/*
|
|
|
|
* Show all sections.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < headp->oh_nsect; i++) {
|
|
|
|
printf("Section %d:\n", i);
|
|
|
|
showsect();
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Show relocation information.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < headp->oh_nrelo; i++) {
|
|
|
|
printf("Relocation record %d:\n", i);
|
|
|
|
showrelo();
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We get all struct outname's and the strings in core first.
|
|
|
|
*/
|
2013-05-29 13:48:51 +00:00
|
|
|
name = (struct outname *) myalloc(headp->oh_nname * sizeof(struct outname));
|
1987-03-11 17:12:23 +00:00
|
|
|
string = myalloc((unsigned) headp->oh_nchar);
|
1987-04-08 15:10:26 +00:00
|
|
|
rd_name(name, headp->oh_nname);
|
1987-03-11 17:12:23 +00:00
|
|
|
for (np = &name[0]; np < &name[headp->oh_nname]; np++) {
|
1987-04-08 15:10:26 +00:00
|
|
|
if (np->on_foff != 0) {
|
|
|
|
np->on_foff -= OFF_CHAR(*headp);
|
|
|
|
if (np->on_foff >= headp->oh_nchar || np->on_foff < 0) {
|
|
|
|
np->on_mptr = "????";
|
|
|
|
}
|
|
|
|
else np->on_mptr = string + np->on_foff;
|
|
|
|
}
|
1987-03-11 17:12:23 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Transfer strings from file to core.
|
|
|
|
*/
|
|
|
|
rd_string(string, headp->oh_nchar);
|
|
|
|
/*
|
|
|
|
* Now we can show all names.
|
|
|
|
*/
|
|
|
|
for (np = &name[0]; np < &name[headp->oh_nname]; np++) {
|
|
|
|
printf("Name %d:\n", np - name);
|
|
|
|
showname(np);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show flags from header.
|
|
|
|
*/
|
|
|
|
showflags(flagword)
|
1991-12-18 09:45:26 +00:00
|
|
|
unsigned flagword;
|
1987-03-11 17:12:23 +00:00
|
|
|
{
|
|
|
|
if (flagword & HF_LINK) printf("unresolved references left\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show a section.
|
|
|
|
*/
|
|
|
|
showsect()
|
|
|
|
{
|
|
|
|
struct outsect section;
|
|
|
|
|
|
|
|
rd_sect(§ion, 1);
|
2013-05-07 23:48:48 +00:00
|
|
|
printf("\tstartaddress in machine\t0x%lX\n", section.os_base);
|
|
|
|
printf("\tsection size in machine\t0x%lX\n", section.os_size);
|
|
|
|
printf("\tstartaddress in file\t0x%lX\n", section.os_foff);
|
|
|
|
printf("\tsection size in file\t0x%lX\n", section.os_flen);
|
1987-03-11 17:12:23 +00:00
|
|
|
printf("\tsection alignment\t%ld\n", section.os_lign);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show a relocation record.
|
|
|
|
*/
|
|
|
|
showrelo()
|
|
|
|
{
|
|
|
|
struct outrelo relrec;
|
|
|
|
|
|
|
|
rd_relo(&relrec, 1);
|
|
|
|
switch (relrec.or_type & RELSZ) {
|
|
|
|
case RELO1:
|
|
|
|
printf("\t1 byte\n");
|
|
|
|
break;
|
|
|
|
case RELO2:
|
|
|
|
printf("\t2 bytes\n");
|
|
|
|
break;
|
2018-09-09 12:11:11 +00:00
|
|
|
case RELO2HI:
|
|
|
|
printf("\ttop 2 bytes of result\n");
|
|
|
|
break;
|
|
|
|
case RELO2HISAD:
|
|
|
|
printf("\ttop 2 bytes of result, sign adjusted\n");
|
|
|
|
break;
|
1987-03-11 17:12:23 +00:00
|
|
|
case RELO4:
|
|
|
|
printf("\t4 bytes\n");
|
|
|
|
break;
|
2013-05-07 23:48:48 +00:00
|
|
|
case RELOPPC:
|
|
|
|
printf("\tPowerPC 26-bit address\n");
|
|
|
|
break;
|
2017-10-18 19:39:31 +00:00
|
|
|
case RELOPPC_LIS:
|
Add RELOLIS for PowerPC lis with ha16 or hi16.
The new relocation type RELOLIS handles these instructions:
lis RT, ha16[expr] == addis RT, r0, ha16[expr]
lis RT, hi16[expr] == addis RT, r0, hi16[expr]
RELOLIS stores a 32-bit value in the program text. In this value, the
high bit is a ha16 flag, the next 5 bits are the target register RT,
and the low bits are a signed 26-bit offset. The linker replaces this
value with the lis instruction.
The old RELOPPC relocated a ha16/lo16 or hi16/lo16 pair. The new
RELOLIS relocates only a ha16 or hi16, so it is no longer necessary to
have a matching lo16 in the next instruction. The disadvantage is
that RELOLIS has only a signed 26-bit offset, not a 32-bit offset.
Switch the assembler to use RELOLIS for ha16 or hi16 and RELO2 for
lo16. The li32 instruction still uses the old RELOPPC relocation.
This is not the same as my RELOPPC change from my recent mail to
tack-devel (https://sourceforge.net/p/tack/mailman/message/35651528/).
This commit is on a different branch. Here I am throwing away my
RELOPPC change and instead trying RELOLIS.
2017-02-08 16:46:31 +00:00
|
|
|
printf("\tPowerPC lis instruction\n");
|
|
|
|
break;
|
2013-05-17 21:40:50 +00:00
|
|
|
case RELOVC4:
|
|
|
|
printf("\tVideoCore IV address in 32-bit instruction\n");
|
|
|
|
break;
|
2018-09-09 12:11:11 +00:00
|
|
|
case RELOMIPS:
|
|
|
|
printf("\tMIPS b or j instruction\n");
|
|
|
|
break;
|
1987-03-11 17:12:23 +00:00
|
|
|
default:
|
2013-05-07 23:48:48 +00:00
|
|
|
printf("\tunknown relocation type %d\n", relrec.or_type & RELSZ);
|
1987-03-11 17:12:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (relrec.or_type & RELPC) printf("\tpc relative\n");
|
|
|
|
if (relrec.or_type & RELBR) printf("\tbytes reversed\n");
|
|
|
|
if (relrec.or_type & RELWR) printf("\twords reversed\n");
|
|
|
|
printf("\treferencing section\t%d\n", (relrec.or_sect & BMASK) - S_MIN);
|
|
|
|
printf("\treferenced symbol index\t%d\n", relrec.or_nami);
|
|
|
|
printf("\treferencing address\t%ld\n", relrec.or_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show the name in the struct `namep' points to.
|
|
|
|
*/
|
|
|
|
showname(namep)
|
|
|
|
struct outname *namep;
|
|
|
|
{
|
|
|
|
if (namep->on_mptr)
|
|
|
|
printf("\t%s\n", namep->on_mptr);
|
|
|
|
else
|
|
|
|
printf("\tno name\n");
|
|
|
|
switch (namep->on_type & S_TYP) {
|
|
|
|
case S_UND:
|
|
|
|
printf("\tundefined\n");
|
|
|
|
break;
|
|
|
|
case S_ABS:
|
|
|
|
printf("\tabsolute\n");
|
|
|
|
break;
|
1991-10-31 11:04:02 +00:00
|
|
|
case S_CRS:
|
|
|
|
printf("\tcross reference\n");
|
1987-03-11 17:12:23 +00:00
|
|
|
default:
|
1987-04-08 15:10:26 +00:00
|
|
|
printf("\tin section %d\n", (namep->on_type & S_TYP) - S_MIN);
|
1987-03-11 17:12:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (namep->on_type & S_EXT) printf("\texternal\n");
|
1991-10-31 11:04:02 +00:00
|
|
|
if (namep->on_type & S_STB) {
|
|
|
|
printf("\tstab 0x%x\n", namep->on_type >> 8);
|
|
|
|
printf("\tdesc 0x%x\n", namep->on_desc);
|
|
|
|
}
|
|
|
|
else switch (namep->on_type & S_ETC) {
|
1987-03-11 17:12:23 +00:00
|
|
|
case S_SCT:
|
|
|
|
printf("\tsection name\n"); break;
|
|
|
|
case S_LIN:
|
|
|
|
printf("\thll source line item\n"); break;
|
|
|
|
case S_FIL:
|
|
|
|
printf("\thll source file item\n"); break;
|
|
|
|
case S_MOD:
|
|
|
|
printf("\tass src file item\n"); break;
|
|
|
|
case S_COM:
|
|
|
|
printf("\tcommon\n"); break;
|
1990-08-02 15:58:10 +00:00
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("\tstab 0x%x\n", namep->on_type >> 8);
|
|
|
|
printf("\tdesc 0x%x\n", namep->on_desc);
|
1987-03-11 17:12:23 +00:00
|
|
|
}
|
2013-05-07 23:48:48 +00:00
|
|
|
printf("\tvalue 0x%lX\n", namep->on_valu);
|
1987-03-11 17:12:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Core allocation via malloc() but fatal if no core.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
myalloc(u)
|
|
|
|
unsigned int u;
|
|
|
|
{
|
|
|
|
register char *rcp;
|
|
|
|
|
|
|
|
rcp = malloc(u);
|
|
|
|
if (rcp == (char *) 0) {
|
|
|
|
error("Out of core\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return rcp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* VARARGS1 */
|
|
|
|
error(s, a1, a2, a3, a4)
|
|
|
|
char *s;
|
|
|
|
{
|
|
|
|
fflush(stdout);
|
|
|
|
fprintf(stderr, s, a1, a2, a3, a4);
|
|
|
|
}
|
|
|
|
|
|
|
|
rd_fatal()
|
|
|
|
{
|
|
|
|
error("Error in reading the object file\n");
|
|
|
|
exit(1);
|
|
|
|
}
|