fis-gtm/sr_i386/obj_file.c

480 lines
11 KiB
C

/****************************************************************
* *
* Copyright 2001, 2009 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "gtm_string.h"
#include <errno.h>
#include "compiler.h"
#include <rtnhdr.h>
#include "obj_gen.h"
#include "cgp.h"
#include "mdq.h"
#include "cmd_qlf.h"
#include "objlabel.h" /* needed for masscomp.h */
#include "masscomp.h"
#include "stringpool.h"
#include "parse_file.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
#include "gtmio.h"
#include "mmemory.h"
#include "obj_file.h"
LITREF char gtm_release_name[];
LITREF int4 gtm_release_name_len;
GBLREF mliteral literal_chain;
GBLREF char source_file_name[];
GBLREF unsigned short source_name_len;
GBLREF command_qualifier cmd_qlf;
GBLREF mident routine_name;
GBLREF mident module_name;
GBLREF boolean_t run_time;
GBLREF int4 mlmax, mvmax;
GBLREF int4 code_size, lit_addrs, lits_size;
GBLDEF int4 psect_use_tab[GTM_LASTPSECT]; /* bytes of each psect in this module */
GBLREF char object_file_name[];
GBLREF short object_name_len;
GBLREF int object_file_des;
static short int current_psect;
static char emit_buff[OBJ_EMIT_BUF_SIZE]; /* buffer for emit output */
static short int emit_buff_used; /* number of chars in emit_buff */
GBLREF uint4 txtrel_cnt;
static uint4 cdlits;
static struct rel_table *data_rel, *data_rel_end;
static struct rel_table *text_rel, *text_rel_end;
DEBUG_ONLY(static uint4 txtrel_cnt_in_hdr;)
error_def(ERR_OBJFILERR);
void create_object_file(rhdtyp *rhead)
{
int status;
unsigned char rout_len;
uint4 stat;
char obj_name[SIZEOF(mident_fixed) + 5];
mstr fstr;
parse_blk pblk;
struct exec hdr;
error_def(ERR_FILEPARSE);
assert(!run_time);
memset(&pblk, 0, SIZEOF(pblk));
pblk.buffer = object_file_name;
pblk.buff_size = MAX_FBUFF;
/* create the object file */
fstr.len = (MV_DEFINED(&cmd_qlf.object_file) ? cmd_qlf.object_file.str.len : 0);
fstr.addr = cmd_qlf.object_file.str.addr;
rout_len = module_name.len;
memcpy(&obj_name[0], module_name.addr, rout_len);
obj_name[rout_len] = '.';
obj_name[rout_len + 1] = 'o';
obj_name[rout_len + 2] = 0;
pblk.def1_size = rout_len + 2;
pblk.def1_buf = obj_name;
status = parse_file(&fstr, &pblk);
if (!(status & 1))
rts_error(VARLSTCNT(5) ERR_FILEPARSE, 2, fstr.len, fstr.addr, status);
object_name_len = pblk.b_esl;
object_file_name[object_name_len] = 0;
OPEN_OBJECT_FILE(object_file_name, O_CREAT | O_RDWR, object_file_des);
if (FD_INVALID == object_file_des)
rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
memcpy(&rhead->jsb[0], "GTM_CODE", SIZEOF(rhead->jsb));
emit_addr((char *)&rhead->src_full_name.addr - (char *)rhead,
(int4)rhead->src_full_name.addr, (int4 *)&rhead->src_full_name.addr);
emit_addr((char *)&rhead->routine_name.addr - (char *)rhead,
(int4)rhead->routine_name.addr, (int4 *)&rhead->routine_name.addr);
txtrel_cnt += 2;
DEBUG_ONLY(txtrel_cnt_in_hdr = txtrel_cnt;)
set_psect(GTM_CODE, 0);
hdr.a_magic = OMAGIC;
hdr.a_stamp = OBJ_LABEL;
hdr.a_entry = 0;
hdr.a_bss = 0;
hdr.a_text = code_size;
assert(0 == PADLEN(lits_size, NATIVE_WSIZE));
hdr.a_data = lits_size; /* and pad to even # */
hdr.a_syms = (mlmax + cdlits) * SIZEOF(struct nlist);
hdr.a_trsize = txtrel_cnt * SIZEOF(struct relocation_info);
hdr.a_drsize = lit_addrs * SIZEOF(struct relocation_info);
emit_immed((char *)&hdr, SIZEOF(hdr));
memset(psect_use_tab, 0, SIZEOF(psect_use_tab));
emit_immed((char *)rhead, SIZEOF(*rhead));
}
void close_object_file(void)
{
assert(0 == PADLEN(lits_size, NATIVE_WSIZE));
resolve_sym();
output_relocation();
output_symbol();
if (emit_buff_used)
buff_emit();
if ((off_t)-1 == lseek(object_file_des, (off_t)0, SEEK_SET))
rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
}
void drop_object_file(void)
{
int rc;
if (FD_INVALID != object_file_des)
{
UNLINK(object_file_name);
CLOSEFILE_RESET(object_file_des, rc); /* resets "object_file_des" to FD_INVALID */
}
}
GBLREF spdesc stringpool;
void emit_addr(int4 refaddr, int4 offset, int4 *result)
{
struct rel_table *newrel;
if (run_time)
{
unsigned char *ptr;
ptr = stringpool.free;
*result = offset - (int4) ptr;
} else
{ *result = offset + code_size;
newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table));
newrel->next = (struct rel_table *) 0;
newrel->resolve = 0;
newrel->r.r_address = refaddr;
newrel->r.r_symbolnum = N_DATA;
newrel->r.r_pcrel = 0;
newrel->r.r_length = 2;
newrel->r.r_extern = 0;
newrel->r.r_pad = 0;
if (!text_rel)
text_rel = text_rel_end = newrel;
else
{ text_rel_end->next = newrel;
text_rel_end = newrel;
}
}
return;
}
void emit_pidr(int4 refoffset, int4 data_offset, int4 *result)
{
struct rel_table *newrel;
assert(!run_time);
refoffset += code_size;
data_offset += code_size;
*result = data_offset;
newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table));
newrel->next = (struct rel_table *)0;
newrel->resolve = 0;
newrel->r.r_address = refoffset;
newrel->r.r_symbolnum = N_DATA;
newrel->r.r_pcrel = 0;
newrel->r.r_length = 2;
newrel->r.r_extern = 0;
newrel->r.r_pad = 0;
if (!data_rel)
data_rel = data_rel_end = newrel;
else
{ data_rel_end->next = newrel;
data_rel_end = newrel;
}
}
void emit_reference(uint4 refaddr, mstr *name, uint4 *result)
{
struct sym_table *sym;
struct rel_table *newrel;
sym = define_symbol(0, name, 0);
assert(sym);
if (sym->n.n_type == (N_TEXT | N_EXT))
*result = sym->n.n_value;
else
{
newrel = (struct rel_table *) mcalloc(SIZEOF(struct rel_table));
newrel->next = (struct rel_table *)0;
newrel->resolve = 0;
newrel->r.r_address = refaddr;
newrel->r.r_symbolnum = 0;
newrel->r.r_pcrel = 0;
newrel->r.r_length = 2;
newrel->r.r_extern = 1;
newrel->r.r_pad = 0;
if (!text_rel)
text_rel = text_rel_end = newrel;
else
{ text_rel_end->next = newrel;
text_rel_end = newrel;
}
if (sym->resolve)
newrel->resolve = sym->resolve;
sym->resolve = newrel;
*result = 0;
}
}
/*
* emit_immed
*
* Args: buffer of executable code, and byte count to be output.
*/
error_def(ERR_STRINGOFLOW);
void emit_immed(char *source, uint4 size)
{
short int write;
if (run_time)
{
if (stringpool.free + size > stringpool.top)
rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
memcpy(stringpool.free, source, size);
stringpool.free += size;
} else
{ while(size > 0)
{
write = SIZEOF(emit_buff) - emit_buff_used;
write = size < write ? size : write;
memcpy(emit_buff + emit_buff_used, source, write);
size -= write;
source += write;
emit_buff_used += write;
psect_use_tab[current_psect] += write;
if (size)
buff_emit();
}
}
}
/*
* buff_emit
*
* Args: buffer pointer, number of bytes to emit
*/
void buff_emit(void)
{
uint4 stat;
if (-1 == write(object_file_des, emit_buff, emit_buff_used))
rts_error(VARLSTCNT(5) ERR_OBJFILERR, 2, object_name_len, object_file_name, errno);
emit_buff_used = 0;
}
void set_psect(unsigned char psect,unsigned char offset)
{
current_psect = psect;
return;
}
/*
* define_symbol
*
* Args: psect index, symbol name, symbol value.
*
* Description: Buffers a definition of a global symbol with the
* given name and value in the given psect.
*/
static struct sym_table *symbols;
struct sym_table *define_symbol(unsigned char psect, mstr *name, int4 value)
{
int cmp;
struct sym_table *sym, *sym1, *newsym;
sym = symbols;
sym1 = 0;
while(sym)
{
if ((cmp = memvcmp(name->addr, name->len, &sym->name[0], sym->name_len - 1)) <= 0)
break;
sym1 = sym;
sym = sym->next;
}
if (cmp || !sym)
{ newsym = (struct sym_table *) mcalloc(SIZEOF(struct sym_table) + name->len);
newsym->name_len = name->len + 1;
memcpy(&newsym->name[0], name->addr, name->len);
newsym->name[ name->len ] = 0;
newsym->n.n_strx = 0;
newsym->n.n_type = N_EXT;
if (psect == GTM_CODE)
newsym->n.n_type |= N_TEXT; /* if symbol is in GTM_CODE, it is defined */
else
txtrel_cnt++;
newsym->n.n_other = 0;
newsym->n.n_desc = 0;
newsym->n.n_value = value;
newsym->resolve = 0;
newsym->next = sym;
if (sym1)
sym1->next = newsym;
else
symbols = newsym;
cdlits++;
return 0;
}
if (!(sym->n.n_type & N_TEXT))
txtrel_cnt++;
return sym;
}
void resolve_sym(void)
{
uint4 symnum;
struct sym_table *sym;
struct rel_table *rel;
symnum = 0;
sym = symbols;
while (sym)
{ if (sym->resolve)
{ rel = sym->resolve;
while (rel)
{ rel->r.r_symbolnum = symnum;
rel = rel->resolve;
}
}
symnum++;
sym = sym->next;
}
}
void output_relocation(void)
{
struct rel_table *rel;
DEBUG_ONLY(int cnt;)
DEBUG_ONLY(cnt = 0;)
rel = text_rel;
while (rel)
{
emit_immed((char *)&rel->r, SIZEOF(rel->r));
rel = rel->next;
DEBUG_ONLY(cnt++;)
}
assert(cnt == txtrel_cnt_in_hdr);
DEBUG_ONLY(cnt = 0;)
rel = data_rel;
while (rel)
{
emit_immed((char *)&rel->r, SIZEOF(rel->r));
rel = rel->next;
DEBUG_ONLY(cnt++;)
}
assert(cnt == lit_addrs);
}
void output_symbol(void)
{
uint4 string_length;
struct sym_table *sym;
string_length = SIZEOF(int4);
sym = symbols;
while (sym)
{
sym->n.n_strx = string_length;
emit_immed((char *)&sym->n, SIZEOF(sym->n));
string_length += sym->name_len;
sym = sym->next;
}
emit_immed((char *)&string_length, SIZEOF(string_length));
sym = symbols;
while (sym)
{
emit_immed((char *)&sym->name[0], sym->name_len);
sym = sym->next;
}
}
void obj_init(void)
{
cdlits = txtrel_cnt = 0;
data_rel = text_rel = data_rel_end = text_rel_end = 0;
symbols = 0;
}
void emit_literals(void)
{
uint4 offset, padsize;
mliteral *p;
set_psect(GTM_LITERALS, 0);
offset = stringpool.free - stringpool.base;
emit_immed((char *)stringpool.base, offset);
/* comp_lits aligns the start of source path on a NATIVE_WSIZE boundary.*/
padsize = PADLEN(offset, NATIVE_WSIZE);
if (padsize)
{
emit_immed(PADCHARS, padsize);
offset += padsize;
}
emit_immed(source_file_name, source_name_len);
offset += source_name_len;
/* comp_lits aligns the start of routine_name on a NATIVE_WSIZE boundary.*/
padsize = PADLEN(offset, NATIVE_WSIZE);
if (padsize)
{
emit_immed(PADCHARS, padsize);
offset += padsize;
}
emit_immed(routine_name.addr, routine_name.len);
offset += routine_name.len;
/* comp_lits aligns the start of the literal area on a NATIVE_WSIZE boundary.*/
padsize = PADLEN(offset, NATIVE_WSIZE);
if (padsize)
{
emit_immed(PADCHARS, padsize);
offset += padsize;
}
dqloop(&literal_chain, que, p)
{
assert (p->rt_addr == offset);
MV_FORCE_NUMD(&p->v);
if (p->v.str.len)
emit_pidr(p->rt_addr + ((char *) &p->v.str.addr - (char *)&p->v),
p->v.str.addr - (char *) stringpool.base, (int4 *)&p->v.str.addr);
else
p->v.str.addr = 0;
emit_immed((char *)&p->v, SIZEOF(p->v));
offset += SIZEOF(p->v);
}
assert(lits_size == offset);
}