summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2017-02-09 19:43:45 -0500
committermidipix <writeonce@midipix.org>2017-02-11 19:07:51 -0500
commit9c013b63fef168f49246fd69ab0c0ce024a20941 (patch)
tree13ca8a0aab41cb48d7b1e8ef6870e81609da04f5 /src
parent5d3a9331a3ced5aa0898839f651c9ec004c9f6f4 (diff)
downloadmdso-9c013b63fef168f49246fd69ab0c0ce024a20941.tar.bz2
mdso-9c013b63fef168f49246fd69ab0c0ce024a20941.tar.xz
archive generation: added mdso_argen_common().
Diffstat (limited to 'src')
-rw-r--r--src/archive/mdso_argen_common.c292
-rw-r--r--src/object/mdso_objgen_dsometa.c6
-rw-r--r--src/object/mdso_objgen_symentry.c10
-rw-r--r--src/object/mdso_objgen_symfn.c10
-rw-r--r--src/output/mdso_output_error.c1
5 files changed, 319 insertions, 0 deletions
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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mdso/mdso.h>
+#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,"!<arch>\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; symidx<aobj->mapstrsnum; 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; symidx<pobj->mapstrsnum; 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; symidx<pobj->mapstrsnum; 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",
};