1#include <assert.h>2#include <limits.h>3#include <stdint.h>4#include <stdio.h>5#include <stdlib.h>6#include <string.h>78#include <scc/mach.h>9#include <scc/coff32.h>1011#include "../libmach.h"12#include "fun.h"1314struct strtbl {15 char *s;16 long siz;17};1819static void20pack_hdr(int order, unsigned char *buf, FILHDR *hdr)21{22 int n;2324 n = pack(order,25 buf,26 "sslllss",27 hdr->f_magic,28 hdr->f_nscns,29 hdr->f_timdat,30 hdr->f_symptr,31 hdr->f_nsyms,32 hdr->f_opthdr,33 hdr->f_flags);34 assert(n == FILHSZ);35}3637static void38pack_scn(int order, unsigned char *buf, SCNHDR *scn)39{40 int n;4142 if (scn->s_zeroes == 0)43 pack(order, buf, "ll", scn->s_zeroes, scn->s_offset);44 else45 memcpy(buf, scn->s_name, 8);4647 n = pack(order,48 buf + 8,49 "llllllssl",50 scn->s_paddr,51 scn->s_vaddr,52 scn->s_size,53 scn->s_scnptr,54 scn->s_relptr,55 scn->s_lnnoptr,56 scn->s_nrelloc,57 scn->s_nlnno,58 scn->s_flags);59 n += 8;60 assert(n == SCNHSZ);61}6263static void64pack_ent(int order, unsigned char *buf, SYMENT *ent)65{66 int n;6768 if (ent->n_zeroes == 0)69 pack(order, buf, "ll", ent->n_zeroes, ent->n_offset);70 else71 memcpy(buf, ent->n_name, 8);7273 n = pack(order,74 buf + 8,75 "lsscc",76 ent->n_value,77 ent->n_scnum,78 ent->n_type,79 ent->n_sclass,80 ent->n_numaux);81 n += 8;8283 assert(n == SYMESZ);84}8586static void87pack_aux_file(int order, unsigned char *buf, AUXENT *aux)88{8990 if (aux->x_zeroes == 0) {91 memset(buf, 0, sizeof(AUXESZ));92 pack(order, buf, "ll", aux->x_zeroes, aux->x_offset);93 } else {94 memcpy(buf, aux->x_fname, E_FILNMLEN);95 }96}9798static void99pack_aux_scn(int order, unsigned char *buf, AUXENT *aux)100{101 int n;102103 n = pack(order,104 buf,105 "lsslsc",106 aux->x_scnlen,107 aux->x_nreloc,108 aux->x_nlinno,109 aux->x_checksum,110 aux->x_associated,111 aux->x_comdat);112 assert(n == AUXESZ);113}114115static void116pack_aux_fun(int order, unsigned char *buf, AUXENT *aux)117{118 int n;119120 n = pack(order,121 buf,122 "lllls",123 aux->x_tagndx,124 aux->x_fsize,125 aux->x_lnnoptr,126 aux->x_endndx,127 aux->x_tvndx);128 assert(n == AUXESZ);129}130131static void132pack_aux_ary(int order, unsigned char *buf, AUXENT *aux)133{134 int n;135136 n = pack(order,137 buf,138 "lssssss",139 aux->x_tagndx,140 aux->x_lnno,141 aux->x_size,142 aux->x_dimen[0],143 aux->x_dimen[1],144 aux->x_dimen[2],145 aux->x_dimen[3],146 aux->x_tvndx);147 assert(n == AUXESZ);148}149150static void151pack_aux_sym(int order, unsigned char *buf, AUXENT *aux)152{153 int n;154155 n = pack(order,156 buf,157 "lsslls",158 aux->x_tagndx,159 aux->x_lnno,160 aux->x_size,161 aux->x_lnnoptr,162 aux->x_endndx,163 aux->x_tvndx);164 assert(n == AUXESZ);165}166167static void168pack_aout(int order, unsigned char *buf, AOUTHDR *aout)169{170 int n;171172 n = pack(order,173 buf,174 "ssllllll",175 aout->magic,176 aout->vstamp,177 aout->tsize,178 aout->dsize,179 aout->bsize,180 aout->entry,181 aout->text_start,182 aout->data_start);183 assert(n == AOUTSZ);184}185186static void187pack_reloc(int order, unsigned char *buf, RELOC *rel)188{189 int n;190191 n = pack(order,192 buf,193 "lls",194 rel->r_vaddr,195 rel->r_symndx,196 rel->r_type);197 assert(n == RELSZ);198}199200static void201pack_line(int order, unsigned char *buf, LINENO *lp)202{203 int n;204205 n = pack(order,206 buf,207 "lls",208 lp->l_addr.l_symndx,209 lp->l_lnno);210 assert(n == LINESZ);211}212213static int214writehdr(Obj *obj, FILE *fp)215{216 FILHDR *hdr;217 struct coff32 *coff;218 unsigned char buf[FILHSZ];219220 coff = obj->data;221 hdr = &coff->hdr;222223 pack_hdr(ORDER(obj->type), buf, hdr);224 if (fwrite(buf, FILHSZ, 1, fp) != 1)225 return 0;226227 return 1;228}229230static int231allocstring(struct coff32 *coff, long off, struct strtbl *tbl)232{233 char *s, *name;234 long len, siz;235236 siz = tbl->siz;237 name = &coff->strtbl[off];238 len = strlen(name) + 1;239 if (len > siz - LONG_MAX)240 return 0;241242 s = realloc(tbl->s, siz + len);243 if (!s)244 return 0;245 memcpy(s + siz, name, len);246247 tbl->s = s;248 tbl->siz += len;249250 return 1;251}252253static int254writescns(Obj *obj, FILE *fp, struct strtbl *tbl)255{256 int i;257 SCNHDR *scn;258 FILHDR *hdr;259 struct coff32 *coff;260 unsigned char buf[SCNHSZ];261262 coff = obj->data;263 hdr = &coff->hdr;264265 for (i = 0; i < hdr->f_nscns; i++) {266 scn = &coff->scns[i];267 if (scn->s_zeroes == 0) {268 if (!allocstring(coff, scn->s_offset, tbl))269 return 0;270 }271 pack_scn(ORDER(obj->type), buf, scn);272 if (fwrite(buf, SCNHSZ, 1, fp) != 1)273 return 0;274 }275276 return 1;277}278279static int280writeents(Obj *obj, FILE *fp, struct strtbl *tbl)281{282 long i;283 FILHDR *hdr;284 struct coff32 *coff;285 unsigned char buf[SYMESZ];286287 coff = obj->data;288 hdr = &coff->hdr;289290 if (!coff->ents)291 return 1;292293 for (i = 0; i < hdr->f_nsyms; i++) {294 SYMENT *ent;295 AUXENT *aux;296 Entry *ep = &coff->ents[i];297298 aux = &ep->u.aux;299 switch (ep->type) {300 case SYM_ENT:301 ent = &ep->u.sym;302 if (ent->n_zeroes == 0) {303 if (!allocstring(coff, ent->n_offset, tbl))304 return 0;305 }306 pack_ent(ORDER(obj->type), buf, ent);307 break;308 case SYM_AUX_UNK:309 memcpy(buf, ep->u.buf, AUXESZ);310 break;311 case SYM_AUX_SYM:312 pack_aux_file(ORDER(obj->type), buf, aux);313 break;314 case SYM_AUX_FILE:315 if (aux->x_zeroes == 0) {316 if (!allocstring(coff, aux->x_offset, tbl))317 return 0;318 }319 pack_aux_file(ORDER(obj->type), buf, aux);320 break;321 case SYM_AUX_SCN:322 pack_aux_scn(ORDER(obj->type), buf, aux);323 break;324 case SYM_AUX_FUN:325 pack_aux_fun(ORDER(obj->type), buf, aux);326 break;327 case SYM_AUX_ARY:328 pack_aux_ary(ORDER(obj->type), buf, aux);329 break;330 }331332 if (fwrite(buf, SYMESZ, 1, fp) != 1)333 return 0;334 }335336 return 1;337}338339static int340writestr(Obj *obj, FILE *fp, struct strtbl *tbl)341{342 struct coff32 *coff;343 unsigned char buf[4];344345 coff = obj->data;346347 free(coff->strtbl);348 coff->strtbl = tbl->s;349 coff->strsiz = tbl->siz;350 tbl->s = NULL;351 tbl->siz = 0;352353 if ((coff->strsiz & 0xffff) != coff->strsiz)354 return 0;355356 pack(ORDER(obj->type), buf, "l", coff->strsiz);357 fwrite(buf, 4, 1, fp);358 fwrite(coff->strtbl, coff->strsiz, 1, fp);359360 return 1;361}362363static int364writeaout(Obj *obj, FILE *fp)365{366 FILHDR *hdr;367 struct coff32 *coff;368 unsigned char buf[AOUTSZ];369370 coff = obj->data;371 hdr = &coff->hdr;372373 if (hdr->f_opthdr == 0)374 return 1;375 pack_aout(ORDER(obj->type), buf, &coff->aout);376377 return fread(buf, AOUTSZ, 1, fp) != 1;378}379380static int381writereloc(Obj *obj, FILE *fp)382{383 int i, j;384 RELOC *rp;385 SCNHDR *scn;386 FILHDR *hdr;387 struct coff32 *coff;388 unsigned char buf[RELSZ];389390 coff = obj->data;391 hdr = &coff->hdr;392393 if (!coff->rels)394 return 1;395396 for (i = 0; i < hdr->f_nscns; i++) {397 rp = coff->rels[i];398 if (!rp)399 continue;400 scn = &coff->scns[i];401402 for (j = 0; j < scn->s_nrelloc; j++) {403 pack_reloc(ORDER(obj->type), buf, &rp[i]);404 if (fwrite(buf, RELSZ, 1, fp) != 1)405 return 0;406 }407 }408409 return 1;410}411412static int413writelines(Obj *obj, FILE *fp)414{415 int i;416 long j;417 LINENO *lp;418 SCNHDR *scn;419 struct coff32 *coff = obj->data;420 FILHDR *hdr = &coff->hdr;421 unsigned char buf[LINESZ];422423 if (!coff->lines)424 return 1;425426 for (i = 0; i < hdr->f_nscns; i++) {427 lp = coff->lines[i];428 if (!lp)429 continue;430 scn = &coff->scns[i];431 for (j = 0; j < scn->s_nlnno; j++) {432 pack_line(ORDER(obj->type), buf, &lp[j]);433 if (fwrite(buf, LINESZ, 1, fp) == 1)434 return 0;435 }436 }437438 return 1;439}440441static int442writedata(Obj *obj, Map *map, FILE *fp)443{444 long n;445 int id, nsec;446 Mapsec *msec;447 Section *sec;448 struct coff32 *coff = obj->data;449 FILHDR *hdr = &coff->hdr;450 SCNHDR *scn;451452 nsec = hdr->f_nscns;453 for (scn = coff->scns; nsec--; scn++) {454 if ((id = findsec(map, scn->s_name)) < 0)455 continue;456 msec = &map->sec[id];457 sec = &msec->sec;458 if (!msec->fp)459 continue;460461 if (copysec(msec, fp) < 0)462 return -1;463 }464465 return 1;466}467468int469coff32write(Obj *obj, Map *map, FILE *fp)470{471 int id;472 long ptr, n;473 SCNHDR *scn;474 Mapsec *sec;475 struct strtbl tbl;476 struct coff32 *coff = obj->data;477 FILHDR *hdr = &coff->hdr;478479 ptr = ftell(fp);480 obj->pos = ptr;481 tbl.s = NULL;482 tbl.siz = 0;483484 n = hdr->f_nscns;485 ptr += FILHSZ + hdr->f_opthdr + n*SCNHSZ;486 for (scn = coff->scns; n--; scn++) {487 scn->s_scnptr = 0;488 if ((id = findsec(map, scn->s_name)) < 0)489 continue;490 sec = &map->sec[id];491 if (!sec->fp)492 continue;493494 scn->s_scnptr = ptr;495 ptr += scn->s_size;496 }497 hdr->f_symptr = (hdr->f_nsyms > 0) ? ptr : 0;498499 n = hdr->f_nscns;500 for (scn = coff->scns; n--; scn++) {501 scn->s_relptr = (scn->s_nrelloc > 0) ? ptr : 0;502 ptr += scn->s_nrelloc * RELSZ;503 }504505 n = hdr->f_nscns;506 for (scn = coff->scns; n--; scn++) {507 scn->s_lnnoptr = (scn->s_nlnno > 0) ? ptr : 0;508 ptr += scn->s_nlnno * RELSZ;509 }510511 /* and now update symbols */512513 if (!writehdr(obj, fp))514 goto err;515 if (!writeaout(obj, fp))516 goto err;517 if (!writescns(obj, fp, &tbl))518 goto err;519 if (!writedata(obj, map, fp))520 goto err;521 if (!writereloc(obj, fp))522 goto err;523 if (!writelines(obj, fp))524 goto err;525 if (!writeents(obj, fp, &tbl))526 goto err;527 if (!writestr(obj, fp, &tbl))528 goto err;529 if (ferror(fp))530 goto err;531 return 0;532533err:534 free(tbl.s);535 return -1;536}