Blame src/object/mdso_objgen_symentry.c

bc1dc4
/****************************************************************/
bc1dc4
/*  mdso: midipix dso scavenger                                 */
473806
/*  Copyright (C) 2015--2024  SysDeer Technologies, LLC         */
bc1dc4
/*  Released under GPLv2 and GPLv3; see COPYING.MDSO.           */
bc1dc4
/****************************************************************/
bc1dc4
bc1dc4
#include <stdio.h>
bc1dc4
#include <stddef.h>
bc1dc4
#include <stdint.h>
bc1dc4
#include <stdlib.h>
bc1dc4
#include <string.h>
a3e2cf
#include <sys/mman.h>
bc1dc4
bc1dc4
#include <mdso/mdso.h>
c26232
#include <mdso/mdso_specs.h>
bc1dc4
#include "mdso_object_impl.h"
bc1dc4
#include "mdso_errinfo_impl.h"
bc1dc4
#include "perk_consts.h"
bc1dc4
#include "perk_structs.h"
bc1dc4
c26232
struct mdso_symfn_refs {
c26232
	unsigned char refs[16];
bc1dc4
};
bc1dc4
bc1dc4
struct mdso_symentry_object {
bc1dc4
	struct pe_raw_coff_object_hdr	hdr;
bc1dc4
	struct pe_raw_sec_hdr		sec[2];
c26232
	struct mdso_symfn_refs		ref[1];
bc1dc4
	struct pe_raw_coff_reloc	rel[2];
bc1dc4
	struct pe_raw_coff_symbol	sym[9];
bc1dc4
	struct pe_raw_coff_strtbl	cst;
bc1dc4
};
bc1dc4
6a7467
static void mdso_obj_write_secoff(unsigned char * ch, uint64_t secoff)
6a7467
{
6a7467
	*ch++ = '/';
6a7467
	mdso_obj_write_dec(ch,secoff);
6a7467
}
6a7467
6a7467
static void mdso_obj_write_sym_symentry(char * ch, const char * sym)
6a7467
{
6a7467
	*ch++ = '.';
6a7467
6a7467
	for (; *sym; )
6a7467
		*ch++ = *sym++;
6a7467
6a7467
	memcpy(ch,"_symentry.s",11);
6a7467
}
6a7467
6a7467
static void mdso_obj_write_sym_symstr(char * ch, const char * sym)
6a7467
{
6a7467
	memcpy(ch,".symstr_",8);
6a7467
	ch = &ch[8];
6a7467
6a7467
	for (; *sym; )
6a7467
		*ch++ = *sym++;
6a7467
}
6a7467
6a7467
static void mdso_obj_write_sym_impstr(char * ch, uint32_t uscore, const char * sym)
6a7467
{
6a7467
	memcpy(ch,"__imp_",6);
6a7467
	ch = &ch[6];
6a7467
6a7467
	if (uscore)
6a7467
		*ch++ = '_';
6a7467
6a7467
	for (; *sym; )
6a7467
		*ch++ = *sym++;
6a7467
}
6a7467
6a7467
static void mdso_obj_write_sym_secstr(char * ch, const char * secname, const char * sym)
6a7467
{
6a7467
	for (; *secname; )
6a7467
		*ch++ = *secname++;
6a7467
6a7467
	*ch++ = '$';
6a7467
6a7467
	for (; *sym; )
6a7467
		*ch++ = *sym++;
6a7467
}
6a7467
6a7467
static void mdso_obj_write_libname(char * ch, const char * secname, const char * sym)
6a7467
{
6a7467
	for (; *secname; )
6a7467
		*ch++ = *secname++;
6a7467
6a7467
	*ch++ = '_';
6a7467
6a7467
	for (; *sym; )
6a7467
		*ch++ = *sym++;
6a7467
}
6a7467
bc1dc4
int mdso_objgen_symentry(
bc1dc4
	const struct mdso_driver_ctx *	dctx,
bc1dc4
	const char *			sym,
bc1dc4
	struct mdso_object *		vobj)
bc1dc4
{
bc1dc4
	struct mdso_symentry_object *	syment;
bc1dc4
	struct pe_raw_coff_symbol *	symrec;
a3e2cf
	void *				addr;
c26232
	void *				mark;
c26232
	char *				ch;
c26232
	char *				strtbl;
bbf7fc
	struct pe_raw_aux_rec_section *	aux;
bc1dc4
	size_t				liblen;
bc1dc4
	uint32_t			symlen;
c26232
	size_t				cstlen;
bc1dc4
	uint32_t			objlen;
bc1dc4
	uint32_t			aattr;
bc1dc4
	uint32_t			sattr;
bc1dc4
	uint32_t			rattr;
bc1dc4
	uint16_t			oattr;
bc1dc4
	uint16_t			machine;
bc1dc4
	uint16_t			reltype;
bc1dc4
	uint32_t			relrva;
bc1dc4
	uint32_t			refoff;
bc1dc4
	uint32_t			reloff;
bc1dc4
	uint32_t			symoff;
9c013b
	uint32_t			uscore;
c26232
	uint32_t			stroff;
c26232
	uint32_t			stroff_cstdata;
c26232
	uint32_t			stroff_file;
c26232
	uint32_t			stroff_dsosyms;
c26232
	uint32_t			stroff_dsostrs;
c26232
	uint32_t			stroff_symstr;
c26232
	uint32_t			stroff_impsym;
c26232
	uint32_t			stroff_libname;
c26232
	uint32_t			stroff_null;
c26232
c26232
	if ((symlen = (uint32_t)strlen(sym)) > 1024*1024)
bc1dc4
		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA);
bc1dc4
bc1dc4
	if ((liblen = strlen(dctx->cctx->libname)) > 1024*1024)
bc1dc4
		return MDSO_CUSTOM_ERROR(dctx,MDSO_ERR_INVALID_DATA);
bc1dc4
c26232
	stroff_cstdata = offsetof(struct pe_raw_coff_strtbl,cst_data);
c26232
	stroff_file    = stroff_cstdata;
c26232
	stroff_dsosyms = stroff_file    + 13 + symlen;   /* .foo_symentry.s  */
c26232
	stroff_dsostrs = stroff_dsosyms + 10 + symlen;   /* .dsosyms$foo     */
c26232
	stroff_symstr  = stroff_dsostrs + 10 + symlen;   /* .dsostrs$foo     */
c26232
	stroff_impsym  = stroff_symstr  + 9  + symlen;   /* .symstr_foo      */
c26232
	stroff_libname = stroff_impsym  + 8  + symlen;   /* __imp__foo       */
c26232
	stroff_null    = stroff_libname + 10 + liblen;   /* .dsometa_libname */
c26232
c26232
	stroff  = offsetof(struct mdso_symentry_object,cst) + stroff_null;
c26232
	stroff += 0xf;
c26232
	stroff |= 0xf;
c26232
	stroff ^= 0xf;
c26232
c26232
	cstlen  = stroff_null;
c26232
	objlen  = stroff + symlen + 1;
c26232
	uscore  = !(dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR);
bc1dc4
a3e2cf
	if (vobj->addr && (vobj->size < objlen))
bc1dc4
		return MDSO_BUFFER_ERROR(dctx);
bc1dc4
a3e2cf
	if ((addr = vobj->addr)) {
a3e2cf
		(void)0;
a3e2cf
a3e2cf
	} else {
a3e2cf
		vobj->size       = objlen;
9c013b
		vobj->mapstrsnum = 1;
9c013b
		vobj->mapstrslen = 7 + uscore + symlen;
bc1dc4
a3e2cf
		if (!vobj->name)
a3e2cf
			return 0;
a3e2cf
a3e2cf
		else if (mdso_create_object(dctx,vobj) < 0)
a3e2cf
			return MDSO_NESTED_ERROR(dctx);
a3e2cf
	}
bc1dc4
a3e2cf
	syment = (struct mdso_symentry_object *)vobj->addr;
bc1dc4
bc1dc4
	if (dctx->cctx->drvflags & MDSO_DRIVER_QUAD_PTR) {
bc1dc4
		aattr   = PE_IMAGE_SCN_ALIGN_16BYTES;
bc1dc4
		machine = PE_IMAGE_FILE_MACHINE_AMD64;
54e94f
		reltype = PE_IMAGE_REL_AMD64_ADDR32NB;
bc1dc4
		relrva  = 8;
bc1dc4
	} else {
bc1dc4
		aattr   = PE_IMAGE_SCN_ALIGN_4BYTES;
bc1dc4
		machine = PE_IMAGE_FILE_MACHINE_I386;
54e94f
		reltype = PE_IMAGE_REL_I386_DIR32NB;
bc1dc4
		relrva  = 4;
bc1dc4
	}
bc1dc4
bc1dc4
	sattr  = PE_IMAGE_SCN_ALIGN_1BYTES;
bc1dc4
	sattr |= PE_IMAGE_SCN_MEM_READ;
bc1dc4
	sattr |= PE_IMAGE_SCN_CNT_INITIALIZED_DATA;
c26232
	sattr |= PE_IMAGE_SCN_LNK_COMDAT;
bc1dc4
bc1dc4
	rattr  = aattr;
bc1dc4
	rattr |= PE_IMAGE_SCN_MEM_READ;
bc1dc4
	rattr |= PE_IMAGE_SCN_CNT_INITIALIZED_DATA;
c26232
	rattr |= PE_IMAGE_SCN_LNK_COMDAT;
bc1dc4
bc1dc4
	oattr  = PE_IMAGE_FILE_LINE_NUMS_STRIPPED;
bc1dc4
	refoff = offsetof(struct mdso_symentry_object,ref);
bc1dc4
	reloff = offsetof(struct mdso_symentry_object,rel);
bc1dc4
	symoff = offsetof(struct mdso_symentry_object,sym);
bc1dc4
bc1dc4
	/* coff object header */
bc1dc4
	mdso_obj_write_short(syment->hdr.cfh_machine,machine);
bc1dc4
	mdso_obj_write_short(syment->hdr.cfh_num_of_sections,2);
bc1dc4
	mdso_obj_write_long(syment->hdr.cfh_ptr_to_sym_tbl,symoff);
bc1dc4
	mdso_obj_write_long(syment->hdr.cfh_num_of_syms,9);
bc1dc4
	mdso_obj_write_short(syment->hdr.cfh_characteristics,oattr);
bc1dc4
bc1dc4
	/* .dsostrs section header */
6a7467
	mdso_obj_write_secoff(syment->sec[0].sh_name,stroff_dsostrs);
bc1dc4
	mdso_obj_write_long(syment->sec[0].sh_size_of_raw_data,symlen+1);
bc1dc4
	mdso_obj_write_long(syment->sec[0].sh_ptr_to_raw_data,stroff);
bc1dc4
	mdso_obj_write_long(syment->sec[0].sh_characteristics,sattr);
bc1dc4
bc1dc4
	/* .dsosyms section header */
6a7467
	mdso_obj_write_secoff(syment->sec[1].sh_name,stroff_dsosyms);
bc1dc4
	mdso_obj_write_long(syment->sec[1].sh_size_of_raw_data,2*relrva);
bc1dc4
	mdso_obj_write_long(syment->sec[1].sh_ptr_to_raw_data,refoff);
bc1dc4
	mdso_obj_write_long(syment->sec[1].sh_ptr_to_relocs,reloff);
bc1dc4
	mdso_obj_write_short(syment->sec[1].sh_num_of_relocs,2);
bc1dc4
	mdso_obj_write_long(syment->sec[1].sh_characteristics,rattr);
bc1dc4
bc1dc4
	/* .dsosyms relocation record: .symstr */
bc1dc4
	mdso_obj_write_long(syment->rel[0].rel_sym,6);
bc1dc4
	mdso_obj_write_long(syment->rel[0].rel_rva,0);
bc1dc4
	mdso_obj_write_short(syment->rel[0].rel_type,reltype);
bc1dc4
bc1dc4
	/* .dsosyms relocation record: .dsometa_libname */
bc1dc4
	mdso_obj_write_long(syment->rel[1].rel_sym,8);
bc1dc4
	mdso_obj_write_long(syment->rel[1].rel_rva,relrva);
bc1dc4
	mdso_obj_write_short(syment->rel[1].rel_type,reltype);
bc1dc4
bc1dc4
	/* coff string table */
bc1dc4
	mdso_obj_write_long(syment->cst.cst_size,cstlen);
c26232
	mark   = &syment->cst;
c26232
	strtbl = mark;
bc1dc4
bc1dc4
	/* coff symbol table */
bc1dc4
	symrec = syment->sym;
bc1dc4
bc1dc4
	/* coff symbol: .file */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_FILE;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 1;
bc1dc4
bc1dc4
	mdso_obj_write_short(&symrec[0].cs_section_number[0],PE_IMAGE_SYM_DEBUG);
c26232
	mdso_obj_write_long(&symrec[1].cs_name[4],stroff_file);
bc1dc4
bc1dc4
	memcpy(symrec[0].cs_name,".file",5);
6a7467
	mdso_obj_write_sym_symentry(&strtbl[stroff_file],sym);
bc1dc4
bc1dc4
	symrec += 2;
bc1dc4
bc1dc4
	/* coff symbol: .dsostrs */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_STATIC;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 1;
bc1dc4
bc1dc4
	mdso_obj_write_short(symrec[0].cs_section_number,1);
c26232
	mdso_obj_write_long(&symrec[0].cs_name[4],stroff_dsostrs);
6a7467
	mdso_obj_write_sym_secstr(&strtbl[stroff_dsostrs],MDSO_STRS_SECTION,sym);
bc1dc4
bbf7fc
	aux = (struct pe_raw_aux_rec_section *)&symrec[1];
bc1dc4
	mdso_obj_write_long(aux->aux_size,symlen+1);
bc1dc4
	mdso_obj_write_short(aux->aux_num_of_relocs,0);
bc1dc4
bc1dc4
	symrec += 2;
bc1dc4
bc1dc4
	/* coff symbol: .dsosyms */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_STATIC;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 1;
bc1dc4
bc1dc4
	mdso_obj_write_short(symrec[0].cs_section_number,2);
c26232
	mdso_obj_write_long(&symrec[0].cs_name[4],stroff_dsosyms);
6a7467
	mdso_obj_write_sym_secstr(&strtbl[stroff_dsosyms],MDSO_SYMS_SECTION,sym);
bc1dc4
bbf7fc
	aux = (struct pe_raw_aux_rec_section *)&symrec[1];
bc1dc4
	mdso_obj_write_long(aux->aux_size,2*relrva);
bc1dc4
	mdso_obj_write_short(aux->aux_num_of_relocs,2);
bc1dc4
bc1dc4
	symrec += 2;
bc1dc4
bc1dc4
	/* coff symbol: .symstr */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_STATIC;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 0;
bc1dc4
bc1dc4
	mdso_obj_write_short(symrec[0].cs_section_number,1);
c26232
	mdso_obj_write_long(&symrec[0].cs_name[4],stroff_symstr);
6a7467
	mdso_obj_write_sym_symstr(&strtbl[stroff_symstr],sym);
bc1dc4
bc1dc4
	symrec += 1;
bc1dc4
bc1dc4
	/* coff symbol: __imp_sym */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 0;
bc1dc4
bc1dc4
	mdso_obj_write_short(symrec[0].cs_section_number,2);
c26232
	mdso_obj_write_long(&symrec[0].cs_name[4],stroff_impsym);
6a7467
	mdso_obj_write_sym_impstr(&strtbl[stroff_impsym],uscore,sym);
bc1dc4
bc1dc4
	symrec += 1;
bc1dc4
9c013b
	/* archive symbol map */
a3e2cf
	if (vobj->mapstrs)
c26232
		strcpy(vobj->mapstrs,&strtbl[stroff_impsym]);
9c013b
bc1dc4
	/* coff symbol: .dsometa_libname */
bc1dc4
	symrec[0].cs_storage_class[0] = PE_IMAGE_SYM_CLASS_EXTERNAL;
bc1dc4
	symrec[0].cs_num_of_aux_symbols[0] = 0;
bc1dc4
bc1dc4
	mdso_obj_write_short(symrec[0].cs_section_number,0);
c26232
	mdso_obj_write_long(&symrec[0].cs_name[4],stroff_libname);
bc1dc4
6a7467
	mdso_obj_write_libname(&strtbl[stroff_libname],
c26232
		MDSO_META_SECTION,
c26232
		dctx->cctx->libname);
bc1dc4
bc1dc4
	/* .symstr */
c26232
	mark = syment;
c26232
	ch   = mark;
c26232
	memcpy(&ch[stroff],sym,symlen);
bc1dc4
a3e2cf
	/* fs object unmap */
a3e2cf
	if (!addr)
a3e2cf
		munmap(vobj->addr,vobj->size);
bc1dc4
a3e2cf
	/* tada */
bc1dc4
	return 0;
bc1dc4
}