/* * patch.c * * patch together the list of ctors and dtors * the order is significant, since we want to * initialize libraries first. * we assume that symbols are in the same order * they were loaded, so we initialize later symbols first. */ #include #include #include #include typedef struct Link Link; typedef void (*Unswab)(ulong, uchar*); struct Link { Link *next; ulong offset; }; Link head; Link x; char *file; long datadel; int debug; void error(char*); Link *findlinks(int, Fhdr*); Link *links(Sym*, Link*); void patch(int, Link *); Unswab nuxi(int, Link); void beunswab(ulong, uchar*); void leunswab(ulong, uchar*); void main(int argc, char *argv[]) { Fhdr hdr; Link *links; int fd; argv0 = *argv; ARGBEGIN{ case 'd': debug = 1; break; }ARGEND if(argc < 1){ fprint(2, "usage: patch [-d] file ...\n"); exits("usage"); } while(argc--){ file = *argv++; fd = open(file, ORDWR); if(!crackhdr(fd, &hdr)) error("can't read header"); links = findlinks(fd, &hdr); patch(fd, links); close(fd); } exits(0); } /* * find the link and header symbols */ Link * findlinks(int fd, Fhdr *hdr) { Link *link; Sym *s; int i; long nsyms; datadel = hdr->datoff - hdr->dataddr; nsyms = syminit(fd, hdr); if(nsyms <= 0) error("can't initialize symbol table"); s = symbase(&nsyms); link = 0; head.offset = 0; for(i = 0; i < nsyms; i++) link = links(s+i, link); return link; } Link * links(Sym *s, Link *link) { if(s->type == 'd'){ if(strcmp("__link", s->name) == 0){ Link *l; l = malloc(sizeof(Link)); if(l == 0) error("out of memory"); l->next = link; l->offset = s->value; return l; } if(strcmp("__head", s->name) == 0) head.offset = s->value; else if(strcmp("__nuxi", s->name) == 0) x.offset = s->value; } return link; } void patch(int fd, Link *link) { Unswab unswab; Link *k; uchar next[4]; ulong crap; unswab = nuxi(fd, x); memset(next, 0, sizeof next); for(k = link; k; k = k->next){ if(debug){ seek(fd, k->offset + datadel, 0); read(fd, &crap, sizeof crap); fprint(2, "link: %lux val %lux\n", k->offset, crap); } if(seek(fd, k->offset + datadel, 0) < 0) error("seek to link failed"); if(write(fd, next, sizeof(next)) < sizeof(next)) error("can't write link"); (*unswab)(k->offset, next); } if(debug){ seek(fd, head.offset + datadel, 0); read(fd, &crap, sizeof crap); fprint(2, "head: %lux val %lux\n", head.offset, crap); } if(seek(fd, head.offset + datadel, 0) < 0) error("seek to head failed\n"); if(write(fd, next, sizeof(next)) < sizeof(next)) error("can't write head"); } Unswab nuxi(int fd, Link x) { uchar beef[4]; if(debug) fprint(2, "nuxi at %d(%d)\n", x.offset, x.offset + datadel); if(seek(fd, x.offset + datadel, 0) < 0) error("seek to nuxi failed"); if(read(fd, beef, sizeof(beef)) < sizeof(beef)) error("can't read nuxi"); if(beef[0] == 0xde && beef[1] == 0xad && beef[2] == 0xbe && beef[3] == 0xef) return beunswab; if(debug) fprint(2, "leunswab\n"); return leunswab; } void beunswab(ulong l, uchar *p) { p[0] = l >> 24; p[1] = l >> 16; p[2] = l >> 8; p[3] = l; } void leunswab(ulong l, uchar *p) { p[0] = l; p[1] = l >> 8; p[2] = l >> 16; p[3] = l >> 24; } void error(char *msg) { fprint(2, "%s: %s for file %s\n", argv0, msg, file); exits(msg); }