347 lines
No EOL
6.4 KiB
C
347 lines
No EOL
6.4 KiB
C
#include "utils/string.h"
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif /* !HAVE_CONFIG_H */
|
|
#include <tcc/state.h>
|
|
#include <tcc/memory.h>
|
|
#include <tcc/object/coff.h>
|
|
#include <tcc/state.h>
|
|
|
|
#define ALIGN_UP(val, alignment) ((val + alignment - 1) & -alignment)
|
|
|
|
#define COFF_DEFAULT_ENTRYNAME "_start"
|
|
|
|
void dynarray_add(void *ptab, int *nb_ptr, void *data);
|
|
void dynarray_reset(void *pp, int *n);
|
|
|
|
static TCCSection *
|
|
coff_new_section(TCCState2 *s1, const char *name, int flags)
|
|
{
|
|
TCCSection *sec;
|
|
|
|
sec = tcc_mallocz(sizeof(TCCSection));
|
|
sec->state = s1;
|
|
strncpy(sec->name, name, 8); /* truncate section name */
|
|
|
|
sec->flags = flags;
|
|
|
|
sec->secnum = s1->nb_sections;
|
|
dynarray_add(&s1->sections, &s1->nb_sections, sec);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
static void
|
|
coff_free_section(TCCSection *s)
|
|
{
|
|
if (!s) return;
|
|
|
|
tcc_free(s->data);
|
|
s->data = NULL;
|
|
s->data_allocated = s->data_offset = 0;
|
|
}
|
|
|
|
void
|
|
coff_new(TCCState2 *s1)
|
|
{
|
|
dynarray_add(&s1->sections, &s1->nb_sections, NULL);
|
|
|
|
s1->text_section = coff_new_section(s1, ".text", COFF_STYP_TEXT);
|
|
s1->data_section = coff_new_section(s1, ".data", COFF_STYP_DATA);
|
|
s1->bss_section = coff_new_section(s1, ".bss", COFF_STYP_BSS);
|
|
s1->rodata_section = coff_new_section(s1, ".rodata", COFF_STYP_RODATA);
|
|
|
|
s1->symtab = tcc_mallocz(sizeof(TCCSymtab)); /* create new symtab */
|
|
/* add dummy symbols */
|
|
s1->symtab->nsym++;
|
|
s1->symtab->syms = tcc_mallocz(sizeof(COFFSym));
|
|
}
|
|
|
|
void
|
|
coff_delete(TCCState2 *s1)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < s1->nb_sections; i++)
|
|
{
|
|
coff_free_section(s1->sections[i]);
|
|
}
|
|
|
|
dynarray_reset(&s1->sections, &s1->nb_sections);
|
|
|
|
if (s1->symtab != NULL)
|
|
{
|
|
tcc_free(s1->symtab->strtab.tab);
|
|
tcc_free(s1->symtab->syms);
|
|
tcc_free(s1->symtab);
|
|
s1->symtab = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
coff_begin_file(TCCState2 *s1)
|
|
{
|
|
TCCSection *sec;
|
|
int i;
|
|
|
|
for (i = 1; i < s1->nb_sections; i++)
|
|
{
|
|
sec = s1->sections[i];
|
|
sec->offset = sec->data_offset;
|
|
}
|
|
}
|
|
|
|
void
|
|
coff_section_realloc(TCCSection *sec, size_t new_size)
|
|
{
|
|
size_t size;
|
|
uint8_t *data;
|
|
|
|
size = sec->data_allocated;
|
|
if (size == 0)
|
|
{
|
|
size = 1;
|
|
}
|
|
|
|
while (size < new_size)
|
|
{
|
|
size = size * 2;
|
|
}
|
|
data = tcc_realloc(sec->data, size);
|
|
memset(data + sec->data_allocated, 0, size - sec->data_allocated);
|
|
sec->data = data;
|
|
sec->data_allocated = size;
|
|
}
|
|
|
|
size_t
|
|
coff_section_add(TCCSection *sec, size_t size, int align)
|
|
{
|
|
size_t offset;
|
|
size_t offset1;
|
|
|
|
offset = ALIGN_UP(sec->data_offset, align);
|
|
offset1 = offset + size;
|
|
if (sec->flags != COFF_STYP_BSS && offset1 > sec->data_allocated)
|
|
{
|
|
coff_section_realloc(sec, offset1);
|
|
}
|
|
sec->data_offset = offset1;
|
|
if (align > sec->addralign)
|
|
{
|
|
sec->addralign = align;
|
|
}
|
|
return (offset);
|
|
}
|
|
|
|
/* reserve at least 'size' bytes in section 'sec' from
|
|
sec->data_offset. */
|
|
void *
|
|
coff_section_ptr_add(TCCSection *sec, size_t size)
|
|
{
|
|
return (sec->data + coff_section_add(sec, size, 1));
|
|
}
|
|
|
|
static TCCSection *
|
|
coff_have_section(TCCState2 *s1, const char *name)
|
|
{
|
|
TCCSection *sec;
|
|
int i;
|
|
|
|
for (i = 1; i < s1->nb_sections; i++)
|
|
{
|
|
sec = s1->sections[i];
|
|
if (strncmp(name, sec->name, 8) == 0)
|
|
{
|
|
return (sec);
|
|
}
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
/* return a reference to a section, and create it if it does not
|
|
exists */
|
|
TCCSection *
|
|
coff_find_section(TCCState2 *s1, const char *name)
|
|
{
|
|
TCCSection *sec;
|
|
|
|
sec = coff_have_section(s1, name);
|
|
if (sec != NULL)
|
|
{
|
|
return (sec);
|
|
}
|
|
|
|
return (coff_new_section(s1, name, COFF_STYP_TEXT));
|
|
}
|
|
|
|
/*
|
|
* ---------------------------------------------------------------------------
|
|
* Symbols
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
coff_add_sym(TCCState2 *s1, uint32_t value, const char *name, size_t size,
|
|
int16_t scnum, uint16_t type, int8_t sclass)
|
|
{
|
|
size_t symidx;
|
|
size_t strtaboffset;
|
|
COFFSym *sym;
|
|
char *ptr;
|
|
|
|
symidx = s1->symtab->nsym;
|
|
s1->symtab->nsym++;
|
|
|
|
s1->symtab->syms = tcc_realloc(s1->symtab->syms, sizeof(COFFSym) * s1->symtab->nsym);
|
|
sym = &(s1->symtab->syms[symidx]);
|
|
if (size > 8)
|
|
{
|
|
strtaboffset = ALIGN_UP(s1->symtab->strtab.len, 1);
|
|
s1->symtab->strtab.len += strtaboffset + size + 1;
|
|
ptr = s1->symtab->strtab.tab;
|
|
s1->symtab->strtab.tab = tcc_realloc(ptr, s1->symtab->strtab.len);
|
|
ptr += strtaboffset;
|
|
memcpy(ptr, name, size + 1);
|
|
|
|
sym->n.n.zeroes = 0x0;
|
|
sym->n.n.offset = strtaboffset;
|
|
}
|
|
else
|
|
{
|
|
memset(sym->n.name, 0, 8);
|
|
memcpy(sym->n.name, name, size);
|
|
}
|
|
|
|
return (symidx);
|
|
}
|
|
|
|
int
|
|
coff_find_sym(TCCState2 *s1, const char *name)
|
|
{
|
|
size_t symidx;
|
|
size_t len;
|
|
COFFSym *sym;
|
|
const char *str;
|
|
|
|
len = strlen(name);
|
|
|
|
for (symidx = 1; symidx < s1->symtab->nsym; symidx++)
|
|
{
|
|
sym = &(s1->symtab->syms[symidx]);
|
|
|
|
if ((len > 8 && sym->n.n.zeroes != 0)
|
|
|| (len <= 8 && sym->n.n.zeroes == 0))
|
|
{
|
|
continue;
|
|
}
|
|
else if (len > 8)
|
|
{
|
|
str = s1->symtab->strtab.tab + sym->n.n.offset;
|
|
if (strcmp(name, str) == 0)
|
|
{
|
|
return (symidx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strncmp(name, sym->n.name, 8) == 0)
|
|
{
|
|
return (symidx);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
uint32_t
|
|
coff_get_sym_addr(TCCState2 *s1, const char *name, int err, int forc)
|
|
{
|
|
COFFSym *sym;
|
|
int sym_idx;
|
|
char buf[256];
|
|
|
|
if (forc && s1->leading_underscore)
|
|
{
|
|
buf[0] = '_';
|
|
pstrcpy(buf + 1, sizeof(buf) - 1, name);
|
|
name = buf;
|
|
}
|
|
|
|
sym_idx = coff_find_sym(s1, name);
|
|
sym = &((COFFSym *)s1->symtab->syms)[sym_idx];
|
|
if (sym_idx == 0 || sym->scnum == COFF_N_UNDEF)
|
|
{
|
|
if (err)
|
|
{
|
|
//_tcc_error_noabort("%s not defined", name);
|
|
}
|
|
return ((uint32_t)-1);
|
|
}
|
|
|
|
return (sym->value);
|
|
}
|
|
|
|
int
|
|
tcc_output_coff(TCCState2 *s1, FILE *f)
|
|
{
|
|
COFFFileHeader coffhdr;
|
|
AOutHeader aouthdr;
|
|
COFFSectionHeader coffsec;
|
|
const char *entry_name = COFF_DEFAULT_ENTRYNAME;
|
|
|
|
memset(&coffhdr, 0, sizeof(COFFFileHeader));
|
|
|
|
coffhdr.flags = COFF_F_LITTLE | COFF_F_LNNO;
|
|
coffhdr.magic = COFF_MAGIC;
|
|
coffhdr.nscns = s1->nb_sections;
|
|
|
|
if (s1->output_type == /*TCC_OUTPUT_EXE*/666)
|
|
{
|
|
coffhdr.flags |= COFF_F_RELFLG | COFF_F_EXEC | COFF_F_LSYMS;
|
|
coffhdr.nsyms = 0;
|
|
|
|
memset(&aouthdr, 0, sizeof(AOutHeader));
|
|
|
|
aouthdr.magic = AOUT_ZMAGIC;
|
|
coffhdr.opthdr = sizeof(AOutHeader);
|
|
|
|
if (s1->entryname != NULL)
|
|
{
|
|
entry_name = s1->entryname;
|
|
}
|
|
//aouthdr.entry = get_sym_addr(s1, entry_name, 1, 0);
|
|
|
|
if (s1->nb_errors)
|
|
{
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
coff_output_object(TCCState2 *s, const char *filename)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
coff_output_exe(TCCState2 *s, const char *filename)
|
|
{
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
coff_load_object(TCCState2 *s, int fd, size_t file_offset)
|
|
{
|
|
COFFFileHeader chdr;
|
|
|
|
|
|
|
|
return (0);
|
|
} |