diff --git a/include/mdso/mdso.h b/include/mdso/mdso.h index 5822880..105a9c5 100644 --- a/include/mdso/mdso.h +++ b/include/mdso/mdso.h @@ -55,6 +55,7 @@ enum mdso_custom_error { MDSO_ERR_INVALID_DSTDIR, MDSO_ERR_INVALID_CONTEXT, MDSO_ERR_INVALID_SOURCE, + MDSO_ERR_INVALID_VECTOR, MDSO_ERR_SOURCE_SIZE_ZERO, MDSO_ERR_CAP, }; @@ -74,7 +75,7 @@ struct mdso_input { struct mdso_object { void * addr; size_t size; - void * mapstrs; + char * mapstrs; uint32_t mapstrsnum; uint32_t mapstrslen; uint32_t arhdrpos; @@ -155,6 +156,7 @@ mdso_api int mdso_asmgen_symfn (const struct mdso_driver_ctx *, const char mdso_api int mdso_objgen_dsometa (const struct mdso_driver_ctx *, FILE * fout, struct mdso_object *); mdso_api int mdso_objgen_symentry (const struct mdso_driver_ctx *, const char * sym, FILE * fout, struct mdso_object *); mdso_api int mdso_objgen_symfn (const struct mdso_driver_ctx *, const char * sym, FILE * fout, struct mdso_object *); +mdso_api int mdso_argen_common (const struct mdso_driver_ctx *, const char ** symv, FILE * fout, struct mdso_object *); #ifdef __cplusplus } diff --git a/project/common.mk b/project/common.mk index 8823bcc..5b1c676 100644 --- a/project/common.mk +++ b/project/common.mk @@ -1,4 +1,5 @@ API_SRCS = \ + src/archive/mdso_argen_common.c \ src/crc/mdso_crc64.c \ src/crc/mdso_crc32.c \ src/driver/mdso_amain.c \ diff --git a/project/tree.mk b/project/tree.mk index ce61482..55b5f90 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,5 +1,6 @@ tree.tag: mkdir -p src + mkdir -p src/archive mkdir -p src/crc mkdir -p src/driver mkdir -p src/helper diff --git a/src/archive/mdso_argen_common.c b/src/archive/mdso_argen_common.c new file mode 100644 index 0000000..95282e3 --- /dev/null +++ b/src/archive/mdso_argen_common.c @@ -0,0 +1,292 @@ +/****************************************************************/ +/* mdso: midipix dso scavenger */ +/* Copyright (C) 2015--2017 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.MDSO. */ +/****************************************************************/ + +#include +#include +#include +#include + +#include +#include "mdso_errinfo_impl.h" +#include "perk_structs.h" + +static void mdso_argen_common_hdr( + struct pe_raw_archive_common_hdr * arhdr, + char * file_id, + size_t size) +{ + size_t slen; + char sbuf[10]; + + memset(arhdr,0x20,sizeof(*arhdr)); + + slen = strlen(file_id); + memcpy(arhdr->ar_file_id,file_id,slen); + arhdr->ar_file_id[slen] = '/'; + + arhdr->ar_uid[0] = '0'; + arhdr->ar_gid[0] = '0'; + arhdr->ar_file_mode[0] = '0'; + + slen = sprintf(sbuf,"%zu",size); + memcpy(arhdr->ar_file_size,sbuf,slen); + + arhdr->ar_end_tag[0] = 0x60; + arhdr->ar_end_tag[1] = 0x0a; +} + +static void mdso_write_big_endian_long(unsigned char * ch, uint32_t val) +{ + ch[3] = val; + ch[2] = val >> 8; + ch[1] = val >> 16; + ch[0] = val >> 24; +} + +int mdso_argen_common( + const struct mdso_driver_ctx * dctx, + const char ** symv, + FILE * fout, + struct mdso_object * vobj) +{ + int ret; + const char ** psym; + int nsym; + int nobj; + uint32_t objlen; + uint32_t hdrlen; + uint32_t mapstrsnum; + uint32_t mapstrslen; + uint32_t symidx; + unsigned char * ar; + unsigned char * mark; + unsigned char * idx; + char * mapstrs; + struct pe_raw_archive_common_hdr * arhdr; + struct mdso_object * pobj; + struct mdso_object * aobj; + struct mdso_object sobj[256]; + char objname[16]; + + /* init */ + memset (sobj,0,sizeof(sobj)); + + for (nsym=0,psym=symv; *psym; psym++) + nsym++; + + if ((nobj = 2*nsym + 1) < 256) + aobj = sobj; + + else if (nobj > 1024*1024) + return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_VECTOR); + + else if (!(aobj = calloc(1,nobj*sizeof(*aobj)))) + return MDSO_SYSTEM_ERROR(dctx); + + /* archive signature, archive header */ + objlen = 8; + objlen += sizeof(struct pe_raw_archive_common_hdr); + + /* archive meta */ + ret = mdso_objgen_dsometa(dctx,0,aobj); + + aobj->size += 1; + aobj->size |= 1; + aobj->size ^= 1; + + objlen += aobj->size; + objlen += aobj->mapstrslen; + objlen += sizeof(uint32_t) * aobj->mapstrsnum; + objlen += sizeof(struct pe_raw_archive_common_hdr); + + mapstrslen = aobj->mapstrslen; + mapstrsnum = aobj->mapstrsnum; + + for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { + ret = mdso_objgen_symfn(dctx,*psym,0,pobj); + + pobj->size += 1; + pobj->size |= 1; + pobj->size ^= 1; + + objlen += pobj->size; + objlen += pobj->mapstrslen; + objlen += sizeof(uint32_t) * pobj->mapstrsnum; + objlen += sizeof(struct pe_raw_archive_common_hdr); + + mapstrslen += pobj->mapstrslen; + mapstrsnum += pobj->mapstrsnum; + pobj++; + + ret |= mdso_objgen_symentry(dctx,*psym,0,pobj); + + pobj->size += 1; + pobj->size |= 1; + pobj->size ^= 1; + + objlen += pobj->size; + objlen += pobj->mapstrslen; + objlen += sizeof(uint32_t) * pobj->mapstrsnum; + objlen += sizeof(struct pe_raw_archive_common_hdr); + + mapstrslen += pobj->mapstrslen; + mapstrsnum += pobj->mapstrsnum; + pobj++; + } + + if (ret && (aobj != sobj)) + free(aobj); + + if (ret) + return ret; + + /* archive alignment */ + mapstrslen += 1; + mapstrslen |= 1; + mapstrslen ^= 1; + + objlen += 15; + objlen |= 15; + objlen ^= 15; + + if (vobj && vobj->addr && (vobj->size < objlen)) + return MDSO_BUFFER_ERROR(dctx); + + if (vobj && !vobj->addr) { + vobj->size = objlen; + vobj->mapstrslen = mapstrslen; + vobj->mapstrsnum = mapstrsnum; + return 0; + } + + if (vobj) + ar = (unsigned char *)vobj->addr; + + else if (!(ar = calloc(1,objlen))) { + if (aobj != sobj) + free(aobj); + + return MDSO_SYSTEM_ERROR(dctx); + } + + /* archive signature */ + memcpy(ar,"!\n",8); + mark = &ar[8]; + + /* archive header */ + arhdr = (struct pe_raw_archive_common_hdr *)mark; + hdrlen = sizeof(uint32_t) * (1 + mapstrsnum) + mapstrslen; + mdso_argen_common_hdr(arhdr,"",hdrlen); + mark += sizeof(*arhdr); + + /* archive index initialization */ + mdso_write_big_endian_long(mark,mapstrsnum); + mark += sizeof(uint32_t); + + idx = mark; + mark += sizeof(uint32_t) * mapstrsnum; + + mapstrs = (char *)mark; + mark += mapstrslen; + + /* .dsometa object */ + aobj->mapstrs = mapstrs; + aobj->arhdrpos = (uint32_t)(mark - ar); + aobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); + aobj->addr = &mark[aobj->arhdrlen]; + + for (symidx=0; symidxmapstrsnum; symidx++) { + mdso_write_big_endian_long(idx,aobj->arhdrpos); + idx += sizeof(uint32_t); + } + + ret = mdso_objgen_dsometa(dctx,0,aobj); + + mdso_argen_common_hdr( + (struct pe_raw_archive_common_hdr *)mark, + ".dsometa.o",aobj->size); + + mark += aobj->arhdrlen + aobj->size; + mapstrs += aobj->mapstrslen; + + /* archive symfn and symentry objects */ + for (psym=symv,pobj=&aobj[1]; *psym && !ret; psym++) { + /* symfn object */ + pobj->mapstrs = mapstrs; + pobj->arhdrpos = (uint32_t)(mark - ar); + pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); + pobj->addr = &mark[pobj->arhdrlen]; + + for (symidx=0; symidxmapstrsnum; symidx++) { + mdso_write_big_endian_long(idx,pobj->arhdrpos); + idx += sizeof(uint32_t); + } + + ret = mdso_objgen_symfn(dctx,*psym,0,pobj); + + sprintf( + objname,"f%06zu.o", + psym - symv); + + mdso_argen_common_hdr( + (struct pe_raw_archive_common_hdr *)mark, + objname,pobj->size); + + mark += pobj->arhdrlen + pobj->size; + mapstrs += pobj->mapstrslen; + pobj++; + + + /* symentry object */ + pobj->mapstrs = mapstrs; + pobj->arhdrpos = (uint32_t)(mark - ar); + pobj->arhdrlen = sizeof(struct pe_raw_archive_common_hdr); + pobj->addr = &mark[pobj->arhdrlen]; + + for (symidx=0; symidxmapstrsnum; symidx++) { + mdso_write_big_endian_long(idx,pobj->arhdrpos); + idx += sizeof(uint32_t); + } + + sprintf( + objname,"s%06zu.o", + psym - symv); + + ret = mdso_objgen_symentry(dctx,*psym,0,pobj); + + mdso_argen_common_hdr( + (struct pe_raw_archive_common_hdr *)mark, + objname,pobj->size); + + mark += pobj->arhdrlen + pobj->size; + mapstrs += pobj->mapstrslen; + pobj++; + } + + if (ret) { + if (aobj != sobj) + free(aobj); + + if (!vobj) + free(ar); + + return ret; + } + + /* tada */ + if (fout) + ret = fwrite(ar,objlen,1,fout); + + if (aobj != sobj) + free(aobj); + + if (!vobj) + free(ar); + + return (ret == 0) + ? MDSO_FILE_ERROR(dctx) + : 0; +} diff --git a/src/object/mdso_objgen_dsometa.c b/src/object/mdso_objgen_dsometa.c index 61df843..dfe8a33 100644 --- a/src/object/mdso_objgen_dsometa.c +++ b/src/object/mdso_objgen_dsometa.c @@ -70,6 +70,8 @@ int mdso_objgen_dsometa( if (vobj && !vobj->addr) { vobj->size = objlen; + vobj->mapstrsnum = 1; + vobj->mapstrslen = 10 + liblen; return 0; } @@ -217,6 +219,10 @@ int mdso_objgen_dsometa( memcpy(&mark[0],".dsometa_",9); memcpy(&mark[9],dctx->cctx->libname,liblen); + /* archive symbol map */ + if (vobj && vobj->mapstrs) + memcpy(vobj->mapstrs,mark,9+liblen); + /* .libname */ mark = dsometa->hdr.cfh_machine; memcpy(&mark[stroff],dctx->cctx->libname,liblen); diff --git a/src/object/mdso_objgen_symentry.c b/src/object/mdso_objgen_symentry.c index 3a3503f..47167c7 100644 --- a/src/object/mdso_objgen_symentry.c +++ b/src/object/mdso_objgen_symentry.c @@ -38,6 +38,7 @@ int mdso_objgen_symentry( struct mdso_symentry_object * syment; struct pe_raw_coff_symbol * symrec; unsigned char * mark; + unsigned char * mapsym; struct pe_raw_aux_rec_section * aux; size_t buflen; size_t liblen; @@ -57,6 +58,7 @@ int mdso_objgen_symentry( uint32_t cstoff; uint32_t datoff; uint32_t stroff; + uint32_t uscore; if ((buflen = strlen(sym)) > 1024*1024) return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA); @@ -67,12 +69,15 @@ int mdso_objgen_symentry( symlen = (uint32_t)buflen; cstlen = (uint32_t)liblen + (3 * symlen) + 64; objlen = sizeof(*syment) + cstlen; + uscore = !(dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR); if (vobj && vobj->addr && (vobj->size < objlen)) return MDSO_BUFFER_ERROR(dctx); if (vobj && !vobj->addr) { vobj->size = objlen; + vobj->mapstrsnum = 1; + vobj->mapstrslen = 7 + uscore + symlen; return 0; } @@ -210,6 +215,7 @@ int mdso_objgen_symentry( symrec += 1; /* coff symbol: __imp_sym */ + mapsym = mark; symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL; symrec[0].cs_num_of_aux_symbols[0] = 0; @@ -231,6 +237,10 @@ int mdso_objgen_symentry( mark += 7 + symlen; symrec += 1; + /* archive symbol map */ + if (vobj && vobj->mapstrs) + memcpy(vobj->mapstrs,mapsym,mark-mapsym); + /* coff symbol: .dsometa_libname */ symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL; symrec[0].cs_num_of_aux_symbols[0] = 0; diff --git a/src/object/mdso_objgen_symfn.c b/src/object/mdso_objgen_symfn.c index 3bdd98f..47f9280 100644 --- a/src/object/mdso_objgen_symfn.c +++ b/src/object/mdso_objgen_symfn.c @@ -53,6 +53,7 @@ int mdso_objgen_symfn( struct pe_raw_coff_symbol * symrec; const unsigned char * code; unsigned char * mark; + unsigned char * mapsym; struct pe_raw_aux_rec_section * aux; size_t buflen; uint32_t symlen; @@ -69,6 +70,7 @@ int mdso_objgen_symfn( uint32_t cstoff; uint32_t codoff; uint32_t datoff; + uint32_t uscore; if ((buflen = strlen(sym)) > 1024*1024) return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA); @@ -76,12 +78,15 @@ int mdso_objgen_symfn( symlen = (uint32_t)buflen; cstlen = (3 * symlen) + 32; objlen = sizeof(*symfn) + cstlen; + uscore = !(dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR); if (vobj && vobj->addr && (vobj->size < objlen)) return MDSO_BUFFER_ERROR(dctx); if (vobj && !vobj->addr) { vobj->size = objlen; + vobj->mapstrsnum = 1; + vobj->mapstrslen = 1 + uscore + symlen; return 0; } @@ -179,6 +184,7 @@ int mdso_objgen_symfn( symrec += 2; /* coff symbol: sym */ + mapsym = mark; symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL; symrec[0].cs_num_of_aux_symbols[0] = 1; @@ -199,6 +205,10 @@ int mdso_objgen_symfn( mark += 1 + symlen; symrec += 2; + /* archive symbol map */ + if (vobj && vobj->mapstrs) + memcpy(vobj->mapstrs,mapsym,mark-mapsym); + /* coff symbol: __imp_sym */ symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL; symrec[0].cs_num_of_aux_symbols[0] = 0; diff --git a/src/output/mdso_output_error.c b/src/output/mdso_output_error.c index 08d66dc..4793a35 100644 --- a/src/output/mdso_output_error.c +++ b/src/output/mdso_output_error.c @@ -27,6 +27,7 @@ static const char const * const mdso_error_strings[MDSO_ERR_CAP] = { [MDSO_ERR_INVALID_DSTDIR] = "invalid destination directory", [MDSO_ERR_INVALID_CONTEXT] = "invalid driver or unit context", [MDSO_ERR_INVALID_SOURCE] = "invalid symbol definition source file", + [MDSO_ERR_INVALID_VECTOR] = "invalid symbol vector, or vector too long", [MDSO_ERR_SOURCE_SIZE_ZERO] = "cannot map an empty symbol definition source file", };