394 lines
13 KiB
C
394 lines
13 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2007, 2010 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. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
/*
|
|
* The native object (ELF) wrapper has the following format:
|
|
*
|
|
* +-------------------------------+
|
|
* | ELF header |
|
|
* +-------------------------------+
|
|
* | .text section (GTM object) |
|
|
* +-------------------------------+
|
|
* | .strtab section(string table) |
|
|
* +-------------------------------+
|
|
* | .symtab section(sym table) |
|
|
* +-------------------------------+
|
|
* | ELF Section header table |
|
|
* +-------------------------------+
|
|
*
|
|
* The GT.M object layout (in the .text section) is described in obj_code.c
|
|
*
|
|
*/
|
|
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_string.h"
|
|
#include <errno.h>
|
|
#include <libelf.h>
|
|
#include "gtm_fcntl.h"
|
|
#include "gtm_unistd.h"
|
|
#include "gtm_stdio.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 "stringpool.h"
|
|
#include "parse_file.h"
|
|
#include "gtmio.h"
|
|
#include "mmemory.h"
|
|
#include "obj_file.h"
|
|
#include "obj_filesp.h"
|
|
#include "release_name.h"
|
|
#include "min_max.h"
|
|
/* The following definitions are reqquired for the new(for ELF files) create/close_obj_file.c functions */
|
|
|
|
#ifdef __linux__
|
|
#define ELF64_LINKER_FLAG 0x10
|
|
#else
|
|
#define ELF64_LINKER_FLAG 0x18
|
|
#endif /* __linux__ */
|
|
|
|
|
|
/* Platform specific action instructions when routine called from foreign language */
|
|
/* Currently just a return to caller on AIX */
|
|
|
|
#define MIN_LINK_PSECT_SIZE 0
|
|
LITDEF mach_inst jsb_action[JSB_ACTION_N_INS] = {0x48, 0xc7, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xc3};
|
|
|
|
|
|
GBLREF command_qualifier cmd_qlf;
|
|
GBLREF char object_file_name[];
|
|
GBLREF int object_file_des;
|
|
GBLREF short object_name_len;
|
|
GBLREF mident module_name;
|
|
GBLREF boolean_t run_time;
|
|
GBLREF int4 gtm_object_size;
|
|
DEBUG_ONLY(GBLREF int obj_bytes_written;)
|
|
|
|
#define GTM_LANG "MUMPS"
|
|
static char static_string_tbl[] = {
|
|
/* Offset 0 */ '\0',
|
|
/* Offset 1 */ '.', 't', 'e', 'x', 't', '\0',
|
|
/* Offset 7 */ '.', 's', 't', 'r', 't', 'a', 'b', '\0',
|
|
/* Offset 15 */ '.', 's', 'y', 'm', 't', 'a', 'b', '\0'
|
|
};
|
|
|
|
#define SPACE_STRING_ALLOC_LEN (SIZEOF(static_string_tbl) + \
|
|
SIZEOF(GTM_LANG) + 1 + \
|
|
SIZEOF(GTM_PRODUCT) + 1 + \
|
|
SIZEOF(GTM_RELEASE_NAME) + 1 + \
|
|
SIZEOF(mident_fixed))
|
|
|
|
/* Following constants has to be in sync with above static string array(static_string_tbl) */
|
|
#define STR_SEC_TEXT_OFFSET 1
|
|
#define STR_SEC_STRTAB_OFFSET 7
|
|
#define STR_SEC_SYMTAB_OFFSET 15
|
|
|
|
#define SEC_TEXT_INDX 1
|
|
#define SEC_STRTAB_INDX 2
|
|
#define SEC_SYMTAB_INDX 3
|
|
|
|
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 mident routine_name;
|
|
GBLREF mident module_name;
|
|
GBLREF int4 mlmax, mvmax;
|
|
GBLREF int4 code_size, lit_addrs, lits_size;
|
|
GBLREF int4 psect_use_tab[]; /* bytes of each psect in this module */
|
|
|
|
error_def(ERR_OBJFILERR);
|
|
|
|
/* Open the object file and write out the gtm object. Actual ELF creation happens at later stage during close_object_file */
|
|
void create_object_file(rhdtyp *rhead)
|
|
{
|
|
int status, rout_len;
|
|
char obj_name[SIZEOF(mident_fixed) + 5];
|
|
mstr fstr;
|
|
parse_blk pblk;
|
|
|
|
error_def(ERR_FILEPARSE);
|
|
|
|
assert(!run_time);
|
|
|
|
DEBUG_ONLY(obj_bytes_written = 0);
|
|
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 = (int)module_name.len;
|
|
memcpy(&obj_name[0], module_name.addr, rout_len);
|
|
memcpy(&obj_name[rout_len], DOTOBJ, SIZEOF(DOTOBJ)); /* includes null terminator */
|
|
pblk.def1_size = rout_len + SIZEOF(DOTOBJ) - 1; /* Length does not include null terminator */
|
|
pblk.def1_buf = obj_name;
|
|
status = parse_file(&fstr, &pblk);
|
|
if (0 == (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);
|
|
|
|
/* Action instructions and marker are not kept in the same array since the type of the elements of
|
|
* the former (uint4) may be different from the type of the elements of the latter (char).
|
|
* 'tiz cleaner this way rather than converting one to the other type in order to be accommodated
|
|
* in an array
|
|
* */
|
|
assert(JSB_ACTION_N_INS * SIZEOF(jsb_action[0]) == SIZEOF(jsb_action)); /* JSB_ACTION_N_INS maintained? */
|
|
assert(SIZEOF(jsb_action) <= SIZEOF(rhead->jsb)); /* overflow check */
|
|
|
|
memcpy(rhead->jsb, (char *)jsb_action, SIZEOF(jsb_action)); /* action instructions */
|
|
memcpy(&rhead->jsb[SIZEOF(jsb_action)], JSB_MARKER, /* followed by GTM_CODE marker */
|
|
MIN(STR_LIT_LEN(JSB_MARKER), SIZEOF(rhead->jsb) - SIZEOF(jsb_action)));
|
|
|
|
emit_immed((char *)rhead, SIZEOF(*rhead));
|
|
}
|
|
|
|
|
|
/* At this point, we know only gtm_object has been written onto the file.
|
|
* Read that gtm_object and wrap it up in .text section, add remaining sections to native object(ELF)
|
|
* Update the ELF, write it out to the object file and close the object file */
|
|
void close_object_file(void)
|
|
{
|
|
int i, status;
|
|
size_t bufSize;
|
|
ssize_t actualSize;
|
|
char *gtm_obj_code, *string_tbl;
|
|
int symIndex, strEntrySize;
|
|
Elf *elf;
|
|
Elf64_Ehdr *ehdr;
|
|
Elf64_Shdr *shdr, *text_shdr, *symtab_shdr, *strtab_shdr;
|
|
Elf_Scn *text_scn, *symtab_scn, *strtab_scn;
|
|
Elf_Data *text_data, *symtab_data, *strtab_data;
|
|
Elf64_Sym symEntries[3];
|
|
|
|
buff_flush();
|
|
bufSize = gtm_object_size;
|
|
actualSize = 0;
|
|
string_tbl = malloc(SPACE_STRING_ALLOC_LEN);
|
|
symIndex = 0;
|
|
|
|
strEntrySize = SIZEOF(static_string_tbl);
|
|
memcpy((string_tbl + symIndex), static_string_tbl, strEntrySize);
|
|
symIndex += strEntrySize;
|
|
|
|
strEntrySize = SIZEOF(GTM_LANG);
|
|
memcpy((string_tbl + symIndex), GTM_LANG, strEntrySize);
|
|
symIndex += strEntrySize;
|
|
|
|
strEntrySize = SIZEOF(GTM_PRODUCT);
|
|
memcpy((string_tbl + symIndex), GTM_PRODUCT, strEntrySize);
|
|
symIndex += strEntrySize;
|
|
|
|
strEntrySize = SIZEOF(GTM_RELEASE_NAME);
|
|
memcpy((string_tbl + symIndex), GTM_RELEASE_NAME, strEntrySize);
|
|
symIndex += strEntrySize;
|
|
|
|
gtm_obj_code = (char *)malloc(bufSize);
|
|
/* At this point, we have only the GTM object written onto the file.
|
|
* We need to read it back and wrap inside the ELF object and
|
|
* write a native ELF object file. */
|
|
lseek(object_file_des, 0, SEEK_SET);
|
|
DOREADRL(object_file_des, gtm_obj_code, bufSize, actualSize);
|
|
/* Reset the pointer back for writing an ELF object. */
|
|
lseek(object_file_des, 0, SEEK_SET);
|
|
|
|
/* Generate ELF64 header */
|
|
if (elf_version(EV_CURRENT) == EV_NONE )
|
|
{
|
|
FPRINTF(stderr, "Elf library out of date!n");
|
|
GTMASSERT;
|
|
}
|
|
if ((elf = elf_begin(object_file_des, ELF_C_WRITE, NULL)) == 0)
|
|
{
|
|
FPRINTF(stderr, "elf_begin failed!\n");
|
|
GTMASSERT;
|
|
}
|
|
if ( (ehdr = elf64_newehdr(elf)) == NULL )
|
|
{
|
|
FPRINTF(stderr, "elf64_newehdr() failed!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
ehdr->e_ident[EI_MAG0] = ELFMAG0;
|
|
ehdr->e_ident[EI_MAG1] = ELFMAG1;
|
|
ehdr->e_ident[EI_MAG2] = ELFMAG2;
|
|
ehdr->e_ident[EI_MAG3] = ELFMAG3;
|
|
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
|
|
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
#ifdef __hpux
|
|
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
|
ehdr->e_ident[EI_OSABI] = ELFOSABI_HPUX;
|
|
#else
|
|
ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
|
|
ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
|
|
#endif /* __hpux */
|
|
ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT;
|
|
ehdr->e_machine = EM_X86_64;
|
|
ehdr->e_type = ET_REL;
|
|
ehdr->e_version = EV_CURRENT;
|
|
ehdr->e_shoff = SIZEOF(Elf64_Ehdr);
|
|
ehdr->e_flags = ELF64_LINKER_FLAG;
|
|
|
|
if ((text_scn = elf_newscn(elf)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newscn() failed for text section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
if ((text_data = elf_newdata(text_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newdata() failed for text section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
text_data->d_align = SECTION_ALIGN_BOUNDARY;
|
|
text_data->d_off = 0LL;
|
|
text_data->d_buf = gtm_obj_code;
|
|
text_data->d_type = ELF_T_REL;
|
|
text_data->d_size = gtm_object_size;
|
|
text_data->d_version = EV_CURRENT;
|
|
|
|
if ((text_shdr = elf64_getshdr(text_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf64_getshdr() failed for text section\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
text_shdr->sh_name = STR_SEC_TEXT_OFFSET;
|
|
text_shdr->sh_type = SHT_PROGBITS;
|
|
text_shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
|
|
text_shdr->sh_entsize = gtm_object_size;
|
|
|
|
memcpy((string_tbl + symIndex), module_name.addr, module_name.len);
|
|
string_tbl[symIndex + module_name.len] = '\0';
|
|
|
|
if ((strtab_scn = elf_newscn(elf)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newscn() failed for strtab section\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
if ((strtab_data = elf_newdata(strtab_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newdata() failed for strtab section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
strtab_data->d_align = NATIVE_WSIZE;
|
|
strtab_data->d_buf = string_tbl;
|
|
strtab_data->d_off = 0LL;
|
|
strtab_data->d_size = SPACE_STRING_ALLOC_LEN;
|
|
strtab_data->d_type = ELF_T_BYTE;
|
|
strtab_data->d_version = EV_CURRENT;
|
|
|
|
if ((strtab_shdr = elf64_getshdr(strtab_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_getshdr() failed for strtab section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
strtab_shdr->sh_name = STR_SEC_STRTAB_OFFSET;
|
|
strtab_shdr->sh_type = SHT_STRTAB;
|
|
strtab_shdr->sh_entsize = 0;
|
|
ehdr->e_shstrndx = elf_ndxscn(strtab_scn);
|
|
|
|
/* Creating .symbtab section */
|
|
i = 0;
|
|
|
|
/* NULL symbol */
|
|
symEntries[i].st_name = 0;
|
|
symEntries[i].st_info = ELF64_ST_INFO(STB_LOCAL, STT_NOTYPE);
|
|
symEntries[i].st_other = STV_DEFAULT;
|
|
symEntries[i].st_shndx = 0;
|
|
symEntries[i].st_size = 0;
|
|
symEntries[i].st_value = 0;
|
|
i++;
|
|
|
|
/* Module symbol */
|
|
symEntries[i].st_name = symIndex;
|
|
symEntries[i].st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC);
|
|
symEntries[i].st_other = STV_DEFAULT;
|
|
symEntries[i].st_shndx = SEC_TEXT_INDX;
|
|
symEntries[i].st_size = gtm_object_size;
|
|
symEntries[i].st_value = 0;
|
|
i++;
|
|
|
|
/* symbol for .text section */
|
|
symEntries[i].st_name = STR_SEC_TEXT_OFFSET;
|
|
symEntries[i].st_info = ELF64_ST_INFO(STB_LOCAL, STT_SECTION);
|
|
symEntries[i].st_other = STV_DEFAULT;
|
|
symEntries[i].st_shndx = SEC_TEXT_INDX; /* index of the .text */
|
|
symEntries[i].st_size = 0;
|
|
symEntries[i].st_value = 0;
|
|
i++;
|
|
|
|
if ((symtab_scn = elf_newscn(elf)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newscn() failed for symtab section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
if ((symtab_data = elf_newdata(symtab_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_newdata() failed for symtab section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
symtab_data->d_align = NATIVE_WSIZE;
|
|
symtab_data->d_off = 0LL;
|
|
symtab_data->d_buf = symEntries;
|
|
symtab_data->d_type = ELF_T_REL;
|
|
symtab_data->d_size = SIZEOF(Elf64_Sym) * i;
|
|
symtab_data->d_version = EV_CURRENT;
|
|
|
|
if ((symtab_shdr = elf64_getshdr(symtab_scn)) == NULL)
|
|
{
|
|
FPRINTF(stderr, "elf_getshdr() failed for symtab section!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
symtab_shdr->sh_name = STR_SEC_SYMTAB_OFFSET;
|
|
symtab_shdr->sh_type = SHT_SYMTAB;
|
|
symtab_shdr->sh_entsize = SIZEOF(Elf64_Sym) ;
|
|
symtab_shdr->sh_link = SEC_STRTAB_INDX;
|
|
|
|
elf_flagehdr(elf, ELF_C_SET, ELF_F_DIRTY);
|
|
if (elf_update(elf, ELF_C_WRITE) < 0)
|
|
{
|
|
FPRINTF(stderr, "elf_update() failed!\n");
|
|
GTMASSERT;
|
|
}
|
|
|
|
elf_end(elf);
|
|
|
|
/* Free the memory malloc'ed above */
|
|
free(string_tbl);
|
|
free(gtm_obj_code);
|
|
|
|
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);
|
|
}
|
|
|