From: Robert Pengelly Date: Sun, 11 May 2025 15:09:18 +0000 (+0100) Subject: Added coff object support and refactor to keep code under 64K X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=2a859233147426f5246e1c9c23d113886f2b1a56;p=sasm.git Added coff object support and refactor to keep code under 64K --- diff --git a/Makefile.p32 b/Makefile.p32 index 77e1a87..5f20489 100644 --- a/Makefile.p32 +++ b/Makefile.p32 @@ -6,7 +6,7 @@ CC=gcc386 LD=ld386 COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__PDOS386__ -D__32BIT__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic -COBJ=as.o bin.o cstr.o elks.o expr.o fixup.o frag.o hashtab.o intel.o kwd.o lex.o lib.o list.o listing.o ll.o macro.o process.o report.o section.o symbol.o vector.o +COBJ=as.o coff.o cstr.o elks.o expr.o fixup.o frag.o hashtab.o intel.o kwd.o lex.o lib.o list.o listing.o ll.o macro.o process.o report.o section.o symbol.o vector.o all: clean sasm.exe diff --git a/Makefile.pdw b/Makefile.pdw index 01ab4cf..13643cf 100644 --- a/Makefile.pdw +++ b/Makefile.pdw @@ -6,7 +6,7 @@ CC=gccwin LD=ldwin COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic -COBJ=as.o bin.o cstr.o elks.o expr.o fixup.o frag.o hashtab.o intel.o kwd.o lex.o lib.o list.o listing.o ll.o macro.o process.o report.o section.o symbol.o vector.o +COBJ=as.o coff.o cstr.o elks.o expr.o fixup.o frag.o hashtab.o intel.o kwd.o lex.o lib.o list.o listing.o ll.o macro.o process.o report.o section.o symbol.o vector.o all: clean sasm.exe diff --git a/Makefile.std b/Makefile.std index 756ac29..7497cde 100644 --- a/Makefile.std +++ b/Makefile.std @@ -8,7 +8,7 @@ LD=pdld COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib \ -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__ -Wall \ -Werror -ansi -m32 -pedantic -COBJ=as.obj bin.obj cstr.obj elks.obj expr.obj fixup.obj frag.obj hashtab.obj \ +COBJ=as.obj coff.obj cstr.obj elks.obj expr.obj fixup.obj frag.obj hashtab.obj \ intel.obj kwd.obj lex.obj lib.obj list.obj listing.obj ll.obj macro.obj \ process.obj report.obj section.obj symbol.obj vector.obj diff --git a/Makefile.unix b/Makefile.unix index 6870fa3..95c06c7 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := as.c bin.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c +CSRC := as.c coff.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c ifeq ($(OS), Windows_NT) all: sasm.exe diff --git a/Makefile.w32 b/Makefile.w32 index 1064347..999c74c 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := as.c bin.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c +CSRC := as.c coff.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c all: sasm.exe diff --git a/Makefile.wat b/Makefile.wat index 788c3d3..acbb2ed 100644 --- a/Makefile.wat +++ b/Makefile.wat @@ -4,7 +4,7 @@ SRCDIR ?= $(CURDIR) VPATH := $(SRCDIR) -SRC := as.c bin.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c +SRC := as.c coff.c cstr.c elks.c expr.c fixup.c frag.c hashtab.c intel.c kwd.c lex.c lib.c list.c listing.c ll.c macro.c process.c report.c section.c symbol.c vector.c all: sasm.exe diff --git a/as.c b/as.c index 961c383..6d3905c 100644 --- a/as.c +++ b/as.c @@ -17,6 +17,7 @@ struct as_state *state = 0; const char *program_name = 0; extern void output_binary (FILE *fp); +extern void output_coff (FILE *fp); extern void output_elks (FILE *fp); extern void keywords_init (void); @@ -59,7 +60,6 @@ int main (int argc, char **argv) { } atexit (cleanup); - lex_init (); state = xmalloc (sizeof (*state)); parse_args (argc, argv, 1); @@ -124,50 +124,6 @@ int main (int argc, char **argv) { return EXIT_FAILURE; } - if (state->format == AS_OUTPUT_BIN) { - - int report_output = 1; - - for (symbol = symbols; symbol; symbol = symbol->next) { - - if ((symbol_is_external (symbol) && symbol_get_section (symbol) == undefined_section) || symbol_is_undefined (symbol)) { - - if (symbol->scope == SYMBOL_SCOPE_GLOBAL) { - - report_at (program_name, 0, REPORT_ERROR, "undefined global symbol '%s'", symbol->name); - continue; - - } - - if (report_output) { - - report_at (program_name, 0, REPORT_ERROR, "%s output does not support external references", state->format == AS_OUTPUT_BIN ? "binary" : "com"); - report_output = 0; - - } - - report_at (program_name, 0, REPORT_ERROR, "undefined external symbol '%s'", symbol->name); - - } - - } - - if (get_error_count () > 0) { - return EXIT_FAILURE; - } - - if (!(state->ofp = fopen (state->ofile, "wb"))) { - - report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->ofile); - return EXIT_FAILURE; - - } - - output_binary (state->ofp); - return EXIT_SUCCESS; - - } - if (!(state->ofp = fopen (state->ofile, "wb"))) { report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->ofile); @@ -175,7 +131,11 @@ int main (int argc, char **argv) { } - output_elks (state->ofp); + if (state->format == AS_OUTPUT_I386_ELKS || state->format == AS_OUTPUT_IA16_ELKS) { + output_elks (state->ofp); + } else if (state->format == AS_OUTPUT_WIN32 || state->format == AS_OUTPUT_WIN64) { + output_coff (state->ofp); + } if (get_error_count () > 0) { return EXIT_FAILURE; diff --git a/as.h b/as.h index 15d33f6..aa97d13 100644 --- a/as.h +++ b/as.h @@ -33,7 +33,8 @@ struct segment { #define AS_OUTPUT_IA16_ELKS 0x00 #define AS_OUTPUT_I386_ELKS 0x01 -#define AS_OUTPUT_BIN 0x02 +#define AS_OUTPUT_WIN32 0x02 +#define AS_OUTPUT_WIN64 0x03 struct as_state { diff --git a/bin.c b/bin.c index a22eaa3..eecb406 100644 --- a/bin.c +++ b/bin.c @@ -23,28 +23,10 @@ void output_binary (FILE *fp) { struct frag *frag; section_set (text_section); - - for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { - - if (frag->fixed_size == 0) { - continue; - } - - text_size += frag->fixed_size; - - } + text_size = section_write_frag_chain (fp); section_set (data_section); - - for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { - - if (frag->fixed_size == 0) { - continue; - } - - data_size += frag->fixed_size; - - } + data_size = section_write_frag_chain (fp); section_set (bss_section); diff --git a/coff.c b/coff.c new file mode 100644 index 0000000..905b842 --- /dev/null +++ b/coff.c @@ -0,0 +1,444 @@ +/****************************************************************************** + * @file coff.c + *****************************************************************************/ +#include +#include +#include +#include + +#include "as.h" +#include "coff.h" +#include "fixup.h" +#include "frag.h" +#include "lib.h" +#include "report.h" +#include "section.h" +#include "stdint.h" +#include "symbol.h" + +static int output_relocation (FILE *outfile, struct fixup *fixup) { + + struct relocation_entry reloc_entry; + unsigned int type = 0; + + if (fixup->add_symbol == NULL) { + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++output relocation fixup->add_symbol is NULL"); + exit (EXIT_FAILURE); + + } + + write_to_byte_array (reloc_entry.VirtualAddress, fixup->frag->address + fixup->where, 4); + + if (symbol_is_section_symbol (fixup->add_symbol) && !SECTION_IS_NORMAL (symbol_get_section (fixup->add_symbol))) { + write_to_byte_array (reloc_entry.SymbolTableIndex, ~(unsigned long) 0, 4); + } else { + write_to_byte_array (reloc_entry.SymbolTableIndex, symbol_get_symbol_table_index (fixup->add_symbol), 4); + } + + if (state->format == AS_OUTPUT_WIN64) { + + switch (fixup->reloc_type) { + + case RELOC_TYPE_DEFAULT: + case RELOC_TYPE_FAR_CALL: + + switch (fixup->size) { + + case 8: + + type = IMAGE_REL_AMD64_ADDR64; + break; + + case 4: + + type = (fixup->pcrel ? IMAGE_REL_AMD64_REL32 : IMAGE_REL_AMD64_ADDR32); + break; + + default: + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "unsupported COFF relocation size %i for reloc_type RELOC_TYPE_DEFAULT", fixup->size); + exit (EXIT_FAILURE); + + } + + break; + + case RELOC_TYPE_RVA: + + if (fixup->size != 4) { + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "unsupported COFF relocation size %i for reloc_type RELOC_TYPE_RVA", fixup->size); + exit (EXIT_FAILURE); + + } + + type = IMAGE_REL_AMD64_ADDR32NB; + break; + + default: + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "output_relocation invalid reloc_type", fixup->reloc_type); + exit (EXIT_FAILURE); + + } + + } else { + + switch (fixup->reloc_type) { + + case RELOC_TYPE_DEFAULT: + case RELOC_TYPE_FAR_CALL: + + switch (fixup->size) { + + case 2: + + type = (fixup->pcrel ? IMAGE_REL_I386_REL16 : IMAGE_REL_I386_DIR16); + break; + + case 4: + + type = (fixup->pcrel ? IMAGE_REL_I386_REL32 : IMAGE_REL_I386_DIR32); + break; + + default: + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "unsupported COFF relocation size %i for reloc_type RELOC_TYPE_DEFAULT", fixup->size); + exit (EXIT_FAILURE); + + } + + break; + + case RELOC_TYPE_RVA: + + type = IMAGE_REL_I386_DIR32NB; + break; + + default: + + report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "output_relocation invalid reloc_type", fixup->reloc_type); + exit (EXIT_FAILURE); + + } + + } + + write_to_byte_array (reloc_entry.Type, type, 2); + + if (fwrite (&reloc_entry, sizeof (reloc_entry), 1, outfile) != 1) { + return 1; + } + + return 0; + +} + +#define GET_UINT16(arr) ((uint32_t) arr[0] | (((uint32_t) arr[1]) << 8)) + +static unsigned long translate_section_flags_to_Characteristics (unsigned int flags) { + + unsigned long Characteristics = 0; + + if (!(flags & SECTION_FLAG_READONLY)) { + Characteristics |= IMAGE_SCN_MEM_WRITE; + } + + if (flags & SECTION_FLAG_CODE) { + Characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE; + } + + if (flags & SECTION_FLAG_DATA) { + Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; + } + + if (flags & SECTION_FLAG_NEVER_LOAD) { + Characteristics |= IMAGE_SCN_TYPE_NOLOAD; + } + + if (flags & SECTION_FLAG_DEBUGGING) { + Characteristics |= IMAGE_SCN_LNK_INFO; + } + + if (flags & SECTION_FLAG_EXCLUDE) { + Characteristics |= IMAGE_SCN_LNK_REMOVE; + } + + if (!(flags & SECTION_FLAG_NOREAD)) { + Characteristics |= IMAGE_SCN_MEM_READ; + } + + if (flags & SECTION_FLAG_SHARED) { + Characteristics |= IMAGE_SCN_MEM_SHARED; + } + + /* .bss */ + if ((flags & SECTION_FLAG_ALLOC) && !(flags & SECTION_FLAG_LOAD)) { + Characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; + } + + if (flags & SECTION_FLAG_LINK_ONCE) { + Characteristics |= IMAGE_SCN_LNK_COMDAT; + } + + return Characteristics; + +} + +void output_coff (FILE *outfile) { + + struct coff_header header; + struct symbol *symbol; + + struct section *section; + unsigned char temp[4]; + + unsigned long string_table_size = 4; + uint32_t NumberOfSymbols = 0; + + sections_number (1); + memset (&header, 0, sizeof (header)); + + if ((outfile = fopen (state->ofile, "wb")) == NULL) { + + report_at (NULL, 0, REPORT_ERROR, "failed to open '%s' as output file", state->ofile); + return; + + } + + write_to_byte_array (header.Machine, (state->format == AS_OUTPUT_WIN64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386), 2); + write_to_byte_array (header.NumberOfSections, sections_get_count (), 2); + write_to_byte_array (header.SizeOfOptionalHeader, 0, 2); + + if (state->format == AS_OUTPUT_WIN64) { + write_to_byte_array (header.Characteristics, IMAGE_FILE_LINE_NUMS_STRIPPED, 2); + } else { + write_to_byte_array (header.Characteristics, IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_32BIT_MACHINE, 2); + } + + if (fseek (outfile, (sizeof (header) + sections_get_count () * sizeof (struct section_table_entry)), SEEK_SET)) { + + report_at (NULL, 0, REPORT_ERROR, "failed to fseek"); + return; + + } + + for (section = sections; section; section = section_get_next_section (section)) { + + uint32_t SizeOfRawData = 0, PointerToRawData = 0; + + struct section_table_entry *section_header = xmalloc (sizeof (*section_header)); + section_set_object_format_dependent_data (section, section_header); + + memset (section_header, 0, sizeof (*section_header)); + + if (strlen (section_get_name (section)) <= 8) { + memcpy (section_header->Name, section_get_name (section), strlen (section_get_name (section))); + } else { + + section_header->Name[0] = '/'; + sprintf (section_header->Name + 1, "%lu", string_table_size); + + string_table_size += strlen (section_get_name (section)) + 1; + + } + + write_to_byte_array (section_header->Characteristics, translate_section_flags_to_Characteristics (section_get_flags (section)), 4); + + if (section != bss_section) { + + PointerToRawData = ftell (outfile); + section_set (section); + + SizeOfRawData = section_write_frag_chain (outfile);; + + if (SizeOfRawData == 0) { + PointerToRawData = 0; + } + + } else { + + struct frag *frag; + + PointerToRawData = 0; + section_set (section); + + for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { + + if (frag->fixed_size == 0) { + continue; + } + + SizeOfRawData += frag->fixed_size; + + } + + } + + write_to_byte_array (section_header->SizeOfRawData, SizeOfRawData, 4); + write_to_byte_array (section_header->PointerToRawData, PointerToRawData, 4); + + } + + write_to_byte_array (header.PointerToSymbolTable, ftell (outfile), 4); + write_to_byte_array (header.NumberOfSymbols, 0, 4); + + for (symbol = symbols; symbol; symbol = symbol->next) { + + struct symbol_table_entry sym_tbl_ent; + + unsigned long value = symbol_get_value (symbol); + unsigned int section_number = 0; + + memset (&sym_tbl_ent, 0, sizeof (sym_tbl_ent)); + + if (symbol->section == undefined_section) { + section_number = IMAGE_SYM_UNDEFINED; + } else if (symbol->section == absolute_section) { + section_number = IMAGE_SYM_ABSOLUTE; + } else { + section_number = section_get_number (symbol->section); + } + + write_to_byte_array (sym_tbl_ent.Type, (IMAGE_SYM_DTYPE_NULL << 8) | IMAGE_SYM_TYPE_NULL, 2); + + if (symbol_is_external (symbol) || symbol_is_undefined (symbol)) { + sym_tbl_ent.StorageClass[0] = IMAGE_SYM_CLASS_EXTERNAL; + } else if (symbol_is_section_symbol (symbol)) { + sym_tbl_ent.StorageClass[0] = IMAGE_SYM_CLASS_STATIC; + } else if (symbol_get_section (symbol) == text_section) { + sym_tbl_ent.StorageClass[0] = IMAGE_SYM_CLASS_LABEL; + } else { + sym_tbl_ent.StorageClass[0] = IMAGE_SYM_CLASS_STATIC; + } + + write_to_byte_array (sym_tbl_ent.Value, value, 4); + sym_tbl_ent.NumberOfAuxSymbols[0] = 0; + + write_to_byte_array (sym_tbl_ent.SectionNumber, section_number, 2); + symbol->write_name_to_string_table = 0; + + if (strlen (symbol->name) <= 8) { + memcpy (sym_tbl_ent.Name, symbol->name, strlen (symbol->name)); + } else { + + memset (sym_tbl_ent.Name, 0, 4); + + write_to_byte_array ((unsigned char *) sym_tbl_ent.Name + 4, string_table_size, 4); + string_table_size += strlen (symbol->name) + 1; + + symbol->write_name_to_string_table = 1; + + } + + if (fwrite (&sym_tbl_ent, sizeof (sym_tbl_ent), 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "error writing symbol table!"); + return; + + } + + symbol_set_symbol_table_index (symbol, NumberOfSymbols); + NumberOfSymbols++; + + } + + write_to_byte_array (header.NumberOfSymbols, NumberOfSymbols, 4); + write_to_byte_array (temp, string_table_size, 4); + + if (fwrite (temp, 4, 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write string table!"); + return; + + } + + for (section = sections; section; section = section_get_next_section (section)) { + + if (strlen (section_get_name (section)) > 8) { + + if (fwrite (section_get_name (section), strlen (section_get_name (section)) + 1, 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write string table!"); + return; + + } + + } + + } + + for (symbol = symbols; symbol; symbol = symbol->next) { + + if (symbol->write_name_to_string_table) { + + if (fwrite (symbol->name, strlen (symbol->name) + 1, 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write string table!"); + return; + + } + + } + + } + + for (section = sections; section; section = section_get_next_section (section)) { + + struct section_table_entry *section_header = section_get_object_format_dependent_data (section); + struct fixup *fixup; + + uint32_t NumberOfRelocations = 0, PointerToRelocations = ftell (outfile); + section_set (section); + + for (fixup = current_frag_chain->first_fixup; fixup; fixup = fixup->next) { + + if (fixup->done) { + continue; + } + + if (output_relocation (outfile, fixup)) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write relocation!"); + return; + + } + + NumberOfRelocations++; + + } + + write_to_byte_array (section_header->NumberOfRelocations, NumberOfRelocations, 2); + + if (NumberOfRelocations == 0) { + PointerToRelocations = 0; + } + + write_to_byte_array (section_header->PointerToRelocations, PointerToRelocations, 4); + + } + + rewind (outfile); + + if (fwrite (&header, sizeof (header), 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write header!"); + return; + + } + + for (section = sections; section; section = section_get_next_section (section)) { + + struct section_table_entry *section_header = section_get_object_format_dependent_data (section); + + if (fwrite (section_header, sizeof (*section_header), 1, outfile) != 1) { + + report_at (NULL, 0, REPORT_ERROR, "failed to write header!"); + return; + + } + + } + +} diff --git a/coff.h b/coff.h new file mode 100644 index 0000000..adc7b8a --- /dev/null +++ b/coff.h @@ -0,0 +1,120 @@ +/****************************************************************************** + * @file coff.h + *****************************************************************************/ +#ifndef _COFF_H +#define _COFF_H + +struct coff_header { + + unsigned char Machine[2]; + unsigned char NumberOfSections[2]; + + unsigned char TimeDateStamp[4]; + unsigned char PointerToSymbolTable[4]; + unsigned char NumberOfSymbols[4]; + + unsigned char SizeOfOptionalHeader[2]; + unsigned char Characteristics[2]; + +}; + +#define IMAGE_FILE_MACHINE_AMD64 0x8664 +#define IMAGE_FILE_MACHINE_I386 0x014C + +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 + +struct section_table_entry { + + char Name[8]; + + unsigned char VirtualSize[4]; + unsigned char VirtualAddress[4]; + + unsigned char SizeOfRawData[4]; + unsigned char PointerToRawData[4]; + unsigned char PointerToRelocations[4]; + unsigned char PointerToLinenumbers[4]; + + unsigned char NumberOfRelocations[2]; + unsigned char NumberOfLinenumbers[2]; + + unsigned char Characteristics[4]; + +}; + +#define IMAGE_SCN_TYPE_NOLOAD 0x00000002 +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Obsolete, means the same as IMAGE_SCN_ALIGN_1BYTES. */ +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 +#define IMAGE_SCN_LNK_INFO 0x00000200 +#define IMAGE_SCN_LNK_REMOVE 0x00000800 +#define IMAGE_SCN_LNK_COMDAT 0x00001000 +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 +#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 + +struct relocation_entry { + + unsigned char VirtualAddress[4]; + unsigned char SymbolTableIndex[4]; + + unsigned char Type[2]; + +}; + +#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 +#define IMAGE_REL_AMD64_ADDR64 0x0001 +#define IMAGE_REL_AMD64_ADDR32 0x0002 +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 +#define IMAGE_REL_AMD64_REL32 0x0004 + +#define IMAGE_REL_I386_ABSOLUTE 0x0000 +#define IMAGE_REL_I386_DIR16 0x0001 +#define IMAGE_REL_I386_REL16 0x0002 +#define IMAGE_REL_I386_DIR32 0x0006 +#define IMAGE_REL_I386_DIR32NB 0x0007 +#define IMAGE_REL_I386_REL32 0x0014 + +struct symbol_table_entry { + + char Name[8]; + unsigned char Value[4]; + + unsigned char SectionNumber[2]; + unsigned char Type[2]; + + unsigned char StorageClass[1]; + unsigned char NumberOfAuxSymbols[1]; + +}; + +#define IMAGE_SYM_UNDEFINED 0 +#define IMAGE_SYM_ABSOLUTE -1 +#define IMAGE_SYM_DEBUG -2 + +#define IMAGE_SYM_TYPE_NULL 0 +#define IMAGE_SYM_DTYPE_NULL 0 + +#define IMAGE_SYM_CLASS_EXTERNAL 2 +#define IMAGE_SYM_CLASS_STATIC 3 +#define IMAGE_SYM_CLASS_LABEL 6 +#define IMAGE_SYM_CLASS_FILE 103 + +#endif /* _COFF_H */ diff --git a/elks.c b/elks.c index fe34633..47ee192 100644 --- a/elks.c +++ b/elks.c @@ -14,16 +14,6 @@ #include "section.h" #include "symbol.h" -static void write_to_byte_array (unsigned char *arr, unsigned long value, int size) { - - int i; - - for (i = 0; i < size; i++) { - arr[i] = (value >> (8 * i)) & 0xff; - } - -} - static int output_relocation (struct fixup *fixup, unsigned long start_address_of_section, FILE *fp) { struct elks_relocation_info reloc; @@ -126,46 +116,12 @@ void output_elks (FILE *fp) { } section_set (text_section); - text_size = 0; - - for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { - - if (frag->fixed_size == 0) { - continue; - } - - if (fwrite (frag->buf, frag->fixed_size, 1, fp) != 1) { - - report_at (program_name, 0, REPORT_ERROR, "failed whilst writing text"); - return; - - } - - text_size += frag->fixed_size; - - } + text_size = section_write_frag_chain (fp); write_to_byte_array (header.a_text, text_size, 4); section_set (data_section); - data_size = 0; - - for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { - - if (frag->fixed_size == 0) { - continue; - } - - if (fwrite (frag->buf, frag->fixed_size, 1, fp) != 1) { - - report_at (program_name, 0, REPORT_ERROR, "failed whilst writing data"); - return; - - } - - data_size += frag->fixed_size; - - } + data_size = section_write_frag_chain (fp); write_to_byte_array (header.a_data, data_size, 4); diff --git a/expr.c b/expr.c index b8400cf..00d0f15 100644 --- a/expr.c +++ b/expr.c @@ -331,7 +331,7 @@ static enum expr_type operator (char *p, unsigned int *operator_size) { static struct section *operand (char *start, char **pp, struct expr *expr, int expr_mode) { struct section *ret_section; - char ch; + char *temp, ch; expr->type = EXPR_TYPE_INVALID; expr->add_number = 0; @@ -345,6 +345,23 @@ static struct section *operand (char *start, char **pp, struct expr *expr, int e goto end_of_line; } + if (**pp >= '0' && **pp <= '9') { + + temp = (*pp); + + while (*temp && (isxdigit (*temp))) { + temp++; + } + + if (*temp && *temp == 'h') { + + *temp = ' '; + goto is_hex; + + } + + } + switch (**pp) { case '1': @@ -371,6 +388,8 @@ static struct section *operand (char *start, char **pp, struct expr *expr, int e (*pp)++; + is_hex: + integer_constant (start, pp, expr, 16); break; diff --git a/fixup.c b/fixup.c index 379fec1..a944fc0 100644 --- a/fixup.c +++ b/fixup.c @@ -237,21 +237,6 @@ static void relax_section (struct section *section) { } - } else if (state->format == AS_OUTPUT_BIN) { - - if (frag->offset == root_frag->offset) { - - frag->relax_type = RELAX_TYPE_NONE_NEEDED; - growth = 0; - - frag->next->address += target; - break; - - } - - frag->relax_type = RELAX_TYPE_NONE_NEEDED; - report_at (frag->filename, frag->line_number, REPORT_ERROR, "program origin redefined"); - } growth = target - (frag->next->address + change); @@ -580,7 +565,7 @@ void fixup_code (void) { finish_frags_after_relaxation (section); } - { + if (state->format == AS_OUTPUT_I386_ELKS || state->format == AS_OUTPUT_IA16_ELKS) { unsigned long address, text_section_size; struct frag *frag; diff --git a/fixup.h b/fixup.h index 833117f..0cf2572 100644 --- a/fixup.h +++ b/fixup.h @@ -8,6 +8,7 @@ #define RELOC_TYPE_DEFAULT 0 #define RELOC_TYPE_FAR_CALL 1 +#define RELOC_TYPE_RVA 2 struct fixup { diff --git a/intel.c b/intel.c index afde45a..c4c7c5a 100644 --- a/intel.c +++ b/intel.c @@ -117,6 +117,8 @@ int operand_type_check (struct operand_type a, enum operand_type_group g) { exit (EXIT_FAILURE); } + + return 0; } @@ -215,6 +217,7 @@ struct relax_table_entry relax_table[] = { static struct hashtab hashtab_templates = { 0 }; static struct hashtab hashtab_regs = { 0 }; +static struct hashtab hashtab_models = { 0 }; #define DEFAULT_CPU_ARCH_NAME "ALL" @@ -1376,6 +1379,26 @@ static struct reg_entry reg_table[] = { }; +struct model_entry { + + const char *name; + unsigned int data_size, model; + +}; + +static struct model_entry model_table[] = { + + { "tiny", 0, 1 }, + { "small", 0, 2 }, + { "compact", 1, 3 }, + { "medium", 0, 4 }, + { "large", 1, 5 }, + { "huge", 2, 6 }, + + { 0, 0, 0 } + +}; + #define BYTE_SUFFIX 'b' #define WORD_SUFFIX 'w' #define SHORT_SUFFIX 's' @@ -1481,6 +1504,31 @@ struct reg_entry *machine_dependent_find_reg_entry (char *name) { } +static struct model_entry *find_model_entry (char *name) { + + char *lname; + + struct hashtab_name *key; + struct model_entry *entry; + + lname = to_lower (name); + + if ((key = hashtab_get_key (&hashtab_models, lname))) { + + if ((entry = hashtab_get (&hashtab_models, key))) { + + free (lname); + return entry; + + } + + } + + free (lname); + return 0; + +} + #define EXPR_TYPE_SHORT EXPR_TYPE_MACHINE_DEPENDENT_0 #define EXPR_TYPE_OFFSET EXPR_TYPE_MACHINE_DEPENDENT_1 @@ -1774,16 +1822,6 @@ static void machine_dependent_set_bits (int new_bits, int cause_fatal_error) { } -static void handler_amd64 (char *start, char **pp) { - - (void) start; - (void) pp; - - machine_dependent_set_march ("generic64"); - machine_dependent_set_bits (64, 0); - -} - static void handler_8086 (char *start, char **pp) { (void) start; @@ -1956,6 +1994,8 @@ static void handler_extern (char *start, char **pp) { static void handler_model (char *start, char **pp) { char *caret = (*pp = skip_whitespace (*pp)); + + struct model_entry *model_entry; char *model, *lang; if (!(model = symname (pp))) { @@ -1969,35 +2009,10 @@ static void handler_model (char *start, char **pp) { *pp = skip_whitespace (*pp); - if (xstrcasecmp (model, "tiny") == 0) { - - state->data_size = 0; - state->model = 1; - - } else if (xstrcasecmp (model, "small") == 0) { - - state->data_size = 0; - state->model = 2; - - } else if (xstrcasecmp (model, "compact") == 0) { - - state->data_size = 1; - state->model = 3; - - } else if (xstrcasecmp (model, "medium") == 0) { + if ((model_entry = find_model_entry (model))) { - state->data_size = 0; - state->model = 4; - - } else if (xstrcasecmp (model, "large") == 0) { - - state->data_size = 1; - state->model = 5; - - } else if (xstrcasecmp (model, "huge") == 0) { - - state->data_size = 2; - state->model = 6; + state->data_size = model_entry->data_size; + state->model = model_entry->model; } else if (xstrcasecmp (model, "flat") == 0) { @@ -2137,8 +2152,6 @@ static void handler_option (char *start, char **pp) { static struct pseudo_op_entry pseudo_op_table[] = { - { ".amd64", &handler_amd64 }, - { ".8086", &handler_8086 }, { ".8087", &handler_8087 }, @@ -2178,6 +2191,8 @@ void machine_dependent_init (void) { struct templates *templates; struct template *template = template_table; + struct model_entry *model_entry; + int ch; templates = xmalloc (sizeof (*templates)); @@ -2268,6 +2283,26 @@ void machine_dependent_init (void) { } + for (model_entry = model_table; model_entry->name; model_entry++) { + + if (hashtab_get_key (&hashtab_models, model_entry->name)) { + + report_at (program_name, 0, REPORT_ERROR, "duplicate entry '%s'", reg_entry->name); + continue; + + } + + if (!(key = hashtab_alloc_name (model_entry->name))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", reg_entry->name); + continue; + + } + + hashtab_put (&hashtab_models, key, model_entry); + + } + for (ch = 0; ch < 255; ch++) { if (islower (ch) || isdigit (ch)) { @@ -2280,8 +2315,22 @@ void machine_dependent_init (void) { expr_type_set_rank (EXPR_TYPE_FULL_PTR, intel_syntax ? 10 : 0); - machine_dependent_set_march ("i8086"); - machine_dependent_set_bits (16, 1); + if (state->format == AS_OUTPUT_WIN64) { + + machine_dependent_set_march ("generic64"); + machine_dependent_set_bits (64, 1); + + } else if (state->format == AS_OUTPUT_I386_ELKS || state->format == AS_OUTPUT_WIN32) { + + machine_dependent_set_march ("i386"); + machine_dependent_set_bits (32, 1); + + } else { + + machine_dependent_set_march ("i8086"); + machine_dependent_set_bits (16, 1); + + } install_pseudo_op_table (pseudo_op_table); @@ -2522,7 +2571,13 @@ static int add_prefix (unsigned char prefix) { int ret = 1; if (bits == 64 && prefix >= REX_PREFIX_OPCODE && prefix < REX_PREFIX_OPCODE + 16) { + prefix_type = REX_PREFIX; + + if (instruction.prefixes[prefix_type] & prefix & ~REX_PREFIX_OPCODE) { + ret = 0; + } + } else { switch (prefix) { @@ -3804,6 +3859,7 @@ static const struct intel_type intel_types[] = { INTEL_TYPE (WORD, 2), INTEL_TYPE (DWORD, 4), INTEL_TYPE (FWORD, 6), + INTEL_TYPE (QWORD, 8), { "near", EXPR_TYPE_NEAR_PTR, { 0xFF02, 0xFF04 } }, { "far", EXPR_TYPE_FAR_PTR, { 0xFF05, 0xFF06 } }, @@ -4385,7 +4441,7 @@ static int match_template (char mnemonic_suffix) { case x86_error_invalid_instruction_suffix: - report_at (get_filename (), get_line_number (), REPORT_ERROR, "invalid instruction suffix for %s", current_templates->name); + report_at (get_filename (), get_line_number (), REPORT_ERROR, "invalid instruction suffix '%c' for %s", mnemonic_suffix, current_templates->name); return 1; case x86_error_operand_size_mismatch: @@ -4411,12 +4467,16 @@ static int match_template (char mnemonic_suffix) { if (state->model < 7) { - if (template->base_opcode == 0xC3 && xstrcasecmp (template->name, "retn") && instruction.operands == 0 && state->model >= 4 && state->procs.length > 0) { - instruction.template.base_opcode = 0xCB; - } + if (xstrcasecmp (template->name, "retn") && instruction.operands == 0 && state->model >= 4 && state->procs.length > 0) { + + if (template->base_opcode == 0xC3) { + instruction.template.base_opcode = 0xCB; + } + + if (template->base_opcode == 0xC2) { + instruction.template.base_opcode = 0xCA; + } - if (template->base_opcode == 0xC2 && xstrcasecmp (template->name, "retn") && instruction.operands == 1 && state->model >= 4 && state->procs.length > 0) { - instruction.template.base_opcode = 0xCA; } } @@ -5479,7 +5539,24 @@ static void output_call_or_jumpbyte (void) { } if (fixup && size == 1) { - fixup->fixup_signed = 1; + + switch (size) { + + case 1: + + fixup->fixup_signed = 1; + break; + + case 4: + + if (bits == 64) { + fixup->fixup_signed = 1; + } + + break; + + } + } } @@ -5555,6 +5632,10 @@ static long convert_number_to_size (unsigned long value, int size) { mask = 0xffffffff; break; + + case 8: + + return value; default: @@ -5590,6 +5671,24 @@ static int disp_size (struct operand_type operand_type) { } +static int imm_size (struct operand_type operand_type) { + + if (operand_type.imm8 || operand_type.imm8s) { + return 1; + } + + if (operand_type.imm16) { + return 2; + } + + if (operand_type.imm64) { + return 8; + } + + return 4; + +} + static void output_disps (void) { int operand; @@ -5607,8 +5706,31 @@ static void output_disps (void) { } else { - fixup_new_expr (current_frag, current_frag->fixed_size, size, instruction.disps[operand], 0, RELOC_TYPE_DEFAULT); + struct fixup *fixup; + int pcrel = (instruction.special_types[operand] & OPERAND_PCREL) != 0; + + if (pcrel) { + + /* pcrel displacement is relative to the end of the instruction, + * so the size of immediate operands has to be included. */ + int operand2; + + for (operand2 = 0; operand2 < instruction.operands; operand2++) { + + if (operand_type_check (instruction.types[operand2], imm)) { + instruction.disps[operand]->add_number -= imm_size (instruction.types[operand2]); + } + + } + + } + + fixup = fixup_new_expr (current_frag, current_frag->fixed_size, size, instruction.disps[operand], pcrel, RELOC_TYPE_DEFAULT); frag_increase_fixed_size (size); + + if (bits == 64 && size == 4 && pcrel && !instruction.prefixes[ADDR_PREFIX]) { + fixup->fixup_signed = 1; + } } @@ -5618,20 +5740,6 @@ static void output_disps (void) { } -static int imm_size (struct operand_type operand_type) { - - if (operand_type.imm8 || operand_type.imm8s) { - return 1; - } - - if (operand_type.imm16) { - return 2; - } - - return 4; - -} - static void output_imms (void) { int operand; @@ -5823,6 +5931,7 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str if (symbol_get_section (frag->symbol) != section) { + struct fixup *fixup; int size = (frag->relax_subtype & RELAX_SUBTYPE_CODE16_JUMP) ? 2 : 4; unsigned char *opcode_pos = frag->buf + frag->opcode_offset_in_buf; @@ -5834,7 +5943,7 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str *opcode_pos = 0xE9; - fixup_new (frag, frag->fixed_size, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); + fixup = fixup_new (frag, frag->fixed_size, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); frag->fixed_size += size; break; @@ -5851,7 +5960,7 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str opcode_pos[2] = 0xE9; frag->fixed_size += 4; - fixup_new (frag, old_frag_fixed_size + 2, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); + fixup = fixup_new (frag, old_frag_fixed_size + 2, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); break; @@ -5864,7 +5973,7 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str opcode_pos[1] = opcode_pos[0] + 0x10; opcode_pos[0] = TWOBYTE_OPCODE; - fixup_new (frag, frag->fixed_size + 1, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); + fixup = fixup_new (frag, frag->fixed_size + 1, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); frag->fixed_size += size + 1; break; @@ -5873,7 +5982,7 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str size = 1; - fixup_new (frag, frag->fixed_size, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); + fixup = fixup_new (frag, frag->fixed_size, size, frag->symbol, frag->offset, 1, RELOC_TYPE_DEFAULT); frag->fixed_size += size; break; @@ -5886,6 +5995,14 @@ signed long machine_dependent_estimate_size_before_relax (struct frag *frag, str } + /** + * Jumps here are signed but wrapping around is allowed, + * only wrapping around at 4 GiB is not allowed in 64-bit mode. + */ + if (size == 4 && bits == 64) { + fixup->fixup_signed = 1; + } + frag->relax_type = RELAX_TYPE_NONE_NEEDED; return frag->fixed_size - old_frag_fixed_size; @@ -6090,7 +6207,7 @@ void machine_dependent_finish_frag (struct frag *frag) { void machine_dependent_assemble_line (char *start, char *line) { - char mnemonic_suffix; + char mnemonic_suffix = 0; memset (&instruction, 0, sizeof (instruction)); memset (operand_exprs, 0, sizeof (operand_exprs)); @@ -6103,6 +6220,10 @@ void machine_dependent_assemble_line (char *start, char *line) { mnemonic_suffix = instruction.suffix; + if (mnemonic_suffix != INTEL_SUFFIX) { + mnemonic_suffix = 0; + } + /** * All Intel instructions have reversed operands except "bound" and some other. * "ljmp" and "lcall" with 2 immediate operands also do not have operands reversed. diff --git a/kwd.c b/kwd.c index 01a2df4..60c014b 100644 --- a/kwd.c +++ b/kwd.c @@ -191,6 +191,8 @@ static void align_bytes (char *start, char **pp, int first_arg_is_bytes) { } +void machine_dependent_number_to_chars (unsigned char *p, unsigned int number, unsigned int size); + static void handle_constant (char *start, char **pp, int size) { struct expr expr, val; @@ -306,13 +308,7 @@ static void handle_constant (char *start, char **pp, int size) { } if (expr.type == EXPR_TYPE_CONSTANT) { - - int i; - - for (i = 0; i < size; i++) { - frag_append_1_char ((expr.add_number >> (8 * i)) & 0xff); - } - + machine_dependent_number_to_chars (frag_increase_fixed_size (size), expr.add_number, size); } else if (expr.type != EXPR_TYPE_INVALID) { fixup_new_expr (current_frag, current_frag->fixed_size, size, &expr, 0, RELOC_TYPE_DEFAULT); diff --git a/lex.c b/lex.c index 7fa85a4..66cade6 100644 --- a/lex.c +++ b/lex.c @@ -3,33 +3,19 @@ *****************************************************************************/ #include "lex.h" -char is_end_of_line[256] = { 0 }; -char lex_table[256] = { 0 }; +char is_end_of_line[256] = { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 /* '\0' and '\n' */ +}; -void lex_init (void) { +char lex_table[256] = { - int i; - - is_end_of_line[0] = 1; - is_end_of_line[10] = 1; - - lex_table[36] = LEX_NAME_START | LEX_NAME_PART; - lex_table[46] = LEX_NAME_START | LEX_NAME_PART; - - for (i = 48; i < 58; i++) { - lex_table[i] = LEX_NAME_PART; - } - - lex_table[63] = LEX_NAME_PART; - - for (i = 65; i < 91; i++) { - lex_table[i] = LEX_NAME_START | LEX_NAME_PART; - } - - lex_table[95] = LEX_NAME_START | LEX_NAME_PART; - - for (i = 97; i < 123; i++) { - lex_table[i] = LEX_NAME_START | LEX_NAME_PART; - } + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* SPACE!"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, /* 0123456789:;<=>? */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, /* #PQRSTUVWXYZ[\]^_ */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 'abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0 /* pqrstuvwxyz{|}~ */ -} +}; diff --git a/lex.h b/lex.h index f295e8b..fe82705 100644 --- a/lex.h +++ b/lex.h @@ -13,6 +13,4 @@ extern char lex_table[]; #define is_name_beginner(c) (lex_table[(c)] & LEX_NAME_START) #define is_name_part(c) (lex_table[(c)] & LEX_NAME_PART) -void lex_init (void); - #endif /* _LEX_H */ diff --git a/lib.c b/lib.c index 9b555c1..dd87125 100644 --- a/lib.c +++ b/lib.c @@ -86,7 +86,8 @@ static void _print_usage (void) { fprintf (stderr, "\n"); fprintf (stderr, " -f FORMAT Specify the format of object file (default elks-ia16)\n"); fprintf (stderr, " Supported formats are:\n"); - fprintf (stderr, " elks-ia16, elks-i386, binary\n"); + fprintf (stderr, " elks-ia16, elks-i386, binary,\n"); + fprintf (stderr, " win32, win64\n"); fprintf (stderr, " -l FILE Print listings to file FILE.\n"); fprintf (stderr, " -o OBJFILE Name the object-file output OBJFILE (default a.out).\n"); @@ -277,6 +278,16 @@ void add_include_path (const char *__p) { } +void write_to_byte_array (unsigned char *arr, unsigned long value, int size) { + + int i; + + for (i = 0; i < size; i++) { + arr[i] = (value >> (8 * i)) & 0xff; + } + +} + void ignore_rest_of_line (char **pp) { while (!is_end_of_line[(int) **pp]) { @@ -393,23 +404,30 @@ void parse_args (int argc, char **argv, int optind) { case AS_OPTION_FORMAT: { - if (xstrcasecmp (optarg, "bin") == 0) { + if (xstrcasecmp (optarg, "elks-ia16") == 0) { - state->format = AS_OUTPUT_BIN; + state->format = AS_OUTPUT_IA16_ELKS; break; } - if (xstrcasecmp (optarg, "elks-ia16") == 0) { + if (xstrcasecmp (optarg, "elks-i386") == 0) { - state->format = AS_OUTPUT_IA16_ELKS; + state->format = AS_OUTPUT_I386_ELKS; break; } - if (xstrcasecmp (optarg, "elks-i386") == 0) { + if (xstrcasecmp (optarg, "win32") == 0) { - state->format = AS_OUTPUT_I386_ELKS; + state->format = AS_OUTPUT_WIN32; + break; + + } + + if (xstrcasecmp (optarg, "win64") == 0) { + + state->format = AS_OUTPUT_WIN64; break; } diff --git a/lib.h b/lib.h index 72e9461..45886b8 100644 --- a/lib.h +++ b/lib.h @@ -18,7 +18,9 @@ int xstrcasecmp (const char *__s1, const char *__s2); int xstrncasecmp (const char *__s1, const char *__s2, unsigned long __len); char *to_lower (const char *__p); + void ignore_rest_of_line (char **pp); +void write_to_byte_array (unsigned char *arr, unsigned long value, int size); void add_include_path (const char *__p); diff --git a/macro.c b/macro.c index f196af6..31c3741 100644 --- a/macro.c +++ b/macro.c @@ -15,26 +15,6 @@ static struct hashtab hashtab_macros = { 0 }; -void remove_all_macros (void) { - - struct macro *m; - int i; - - for (i = 0; i < hashtab_macros.capacity; i++) { - - if (!(m = (struct macro *) &hashtab_macros.entries[i])) { - continue; - } - - free (m->name); - free (m->value); - - } - - memset (&hashtab_macros, 0, sizeof (hashtab_macros)); - -} - struct hashtab_name *find_macro (char *sname) { struct hashtab_name *key; @@ -305,8 +285,6 @@ void remove_macro (char *start, char **pp, int report_line) { if (!(sname = symname (pp))) { - if (!(sname = symname (pp))) { - if (report_line) { report_line_at (get_filename (), get_line_number (), REPORT_ERROR, start, caret, "macro names must be identifiers"); } else { @@ -315,10 +293,6 @@ void remove_macro (char *start, char **pp, int report_line) { return; - } - - return; - } if ((key = find_macro (sname))) { @@ -549,7 +523,3 @@ char *process_macro (char *start, char **pp, struct macro *m) { return m->value; } - -void push_macro (struct hashtab_name *key, struct macro *m) { - hashtab_put (&hashtab_macros, key, m); -} diff --git a/macro.h b/macro.h index 220bef0..7523086 100644 --- a/macro.h +++ b/macro.h @@ -20,15 +20,13 @@ struct macro { }; #include "hashtab.h" + struct hashtab_name *find_macro (char *sname); struct macro *get_macro (struct hashtab_name *key); -void remove_all_macros (void); - void add_macro (char *start, char **pp, int report_line); void remove_macro (char *start, char **pp, int report_line); char *process_macro (char *start, char **pp, struct macro *m); -void push_macro (struct hashtab_name *key, struct macro *m); #endif /* _MACRO_H */ diff --git a/process.c b/process.c index 62fe72f..0402d20 100644 --- a/process.c +++ b/process.c @@ -497,14 +497,14 @@ static struct pp_pseudo_op_entry cond_pseudo_op_table[] = { static struct hashtab hashtab_cond_pseudo_ops = { 0 }; static int includes = 0; -static void install_cond_pseudo_op_table (struct pp_pseudo_op_entry *table) { +static void install_pp_pseudo_op_table (struct pp_pseudo_op_entry *table, struct hashtab *hashatb_table) { struct pp_pseudo_op_entry *entry; struct hashtab_name *key; for (entry = table; entry->name; entry++) { - if (hashtab_get_key (&hashtab_cond_pseudo_ops, entry->name)) { + if (hashtab_get_key (hashatb_table, entry->name)) { report_at (program_name, 0, REPORT_ERROR, "duplicate entry '%s'", entry->name); continue; @@ -518,7 +518,7 @@ static void install_cond_pseudo_op_table (struct pp_pseudo_op_entry *table) { } - hashtab_put (&hashtab_cond_pseudo_ops, key, entry); + hashtab_put (hashatb_table, key, entry); } @@ -682,33 +682,6 @@ static struct pp_pseudo_op_entry pseudo_op_table[] = { }; -static void install_pp_pseudo_op_table (struct pp_pseudo_op_entry *table) { - - struct pp_pseudo_op_entry *entry; - struct hashtab_name *key; - - for (entry = table; entry->name; entry++) { - - if (hashtab_get_key (&hashtab_pseudo_ops, entry->name)) { - - report_at (program_name, 0, REPORT_ERROR, "duplicate entry '%s'", entry->name); - continue; - - } - - if (!(key = hashtab_alloc_name (entry->name))) { - - report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for '%s'", entry->name); - continue; - - } - - hashtab_put (&hashtab_pseudo_ops, key, entry); - - } - -} - struct pp_pseudo_op_entry *find_directive (char *name) { struct hashtab_name *key; @@ -727,29 +700,6 @@ struct pp_pseudo_op_entry *find_directive (char *name) { } -static void init_builtin_macros (void) { - - char *name; - - struct hashtab_name *key; - struct macro *m; - - name = xstrdup ("__SASM__"); - - if ((key = hashtab_alloc_name (name))) { - - m = xmalloc (sizeof (*m)); - m->type = MACRO_BUILTIN; - - m->name = name; - m->value = "1"; - - push_macro (key, m); - - } - -} - int preprocess_init (void) { struct list *item; @@ -758,14 +708,6 @@ int preprocess_init (void) { set_filename (xstrdup ("")); set_line_number (1); - remove_all_macros (); - - while ((opt = vec_pop (&vec_include_paths))) { - free (opt); - } - - init_builtin_macros (); - if (state->pplist) { item = state->pplist; @@ -789,29 +731,25 @@ int preprocess_init (void) { case 'D': - opt = nopt = xstrdup (opt + 2); + nopt = opt + 2; if ((p = strrchr (nopt, '='))) { *p++ = ' '; } add_macro (nopt, &nopt, 0); - free (opt); - break; case 'I': - vec_push (&vec_include_paths, xstrdup (opt + 2)); + vec_push (&vec_include_paths, opt + 2); break; case 'U': - opt = nopt = xstrdup (opt + 2); + nopt = opt + 2; remove_macro (nopt, &nopt, 0); - free (opt); - break; default: @@ -825,8 +763,8 @@ int preprocess_init (void) { } - install_cond_pseudo_op_table (cond_pseudo_op_table); - install_pp_pseudo_op_table (pseudo_op_table); + install_pp_pseudo_op_table (cond_pseudo_op_table, &hashtab_cond_pseudo_ops); + install_pp_pseudo_op_table (pseudo_op_table, &hashtab_pseudo_ops); return get_error_count () > 0; diff --git a/section.c b/section.c index 8922fa4..a640346 100644 --- a/section.c +++ b/section.c @@ -1,21 +1,28 @@ /****************************************************************************** * @file section.c *****************************************************************************/ +#include +#include #include +#include "as.h" #include "frag.h" #include "lib.h" +#include "report.h" #include "section.h" #include "symbol.h" struct section { const char *name; + void *object_format_dependent_data; - struct frag_chain frag_chain; + struct frag_chain *frag_chain; struct symbol *symbol; - int alignment_power; + unsigned int number; + unsigned long flags; + struct section *next; }; @@ -37,6 +44,8 @@ struct section *current_section; struct frag_chain *current_frag_chain = 0; struct section *sections = 0; +unsigned long current_subsection; + static struct section *find_or_make_section_by_name (const char *name) { struct section *section, **p_next; @@ -72,11 +81,38 @@ struct section *section_get_next_section (struct section *section) { struct section *section_set (struct section *section) { + struct frag_chain *frag_chain, **p_next; + unsigned long subsection = 0; + current_section = section; - current_frag_chain = ¤t_section->frag_chain; + for (frag_chain = *(p_next = &(current_section->frag_chain)); frag_chain; frag_chain = *(p_next = &(frag_chain->next))) { + + if (frag_chain->subsection >= subsection) { + break; + } + + } + + if (!frag_chain || frag_chain->subsection != subsection) { + + struct frag_chain *new_frag_chain = xmalloc (sizeof (*new_frag_chain)); + new_frag_chain->subsection = subsection; + + new_frag_chain->last_frag = new_frag_chain->first_frag = frag_alloc (); + new_frag_chain->last_fixup = new_frag_chain->first_fixup = 0; + + *p_next = new_frag_chain; + new_frag_chain->next = frag_chain; + + frag_chain = new_frag_chain; + + } + + current_frag_chain = frag_chain; current_frag = current_frag_chain->last_frag; + current_subsection = subsection; return section; } @@ -93,14 +129,54 @@ const char *section_get_name (struct section *section) { return section->name; } -void section_record_alignment_power (struct section *section, int alignment_power) { +unsigned int section_get_number (struct section *section) { + return section->number; +} + +unsigned int sections_get_count (void) { + + struct section *section; + unsigned int count; + + for (section = sections, count = 0; section; section = section->next, count++); + return count; + +} + +unsigned long section_get_flags (struct section *section) { + return section->flags; +} - if (alignment_power > section->alignment_power) { - section->alignment_power = alignment_power; +unsigned long section_write_frag_chain (FILE *fp) { + + struct frag *frag; + unsigned long bytes = 0; + + for (frag = current_frag_chain->first_frag; frag; frag = frag->next) { + + if (frag->fixed_size == 0) { + continue; + } + + if (fwrite (frag->buf, frag->fixed_size, 1, fp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing data"); + return bytes; + + } + + bytes += frag->fixed_size; + } + + return bytes; } +void section_set_flags (struct section *section, unsigned long flags) { + section->flags = flags; +} + #define CREATE_INTERNAL_SECTION(section_var, section_name, section_index) \ (section_var) = &internal_sections[(section_index)]; \ @@ -120,16 +196,13 @@ void sections_init (void) { CREATE_INTERNAL_SECTION (reg_section, "*REG*", 3); text_section = section_set_by_name (".text"); - text_section->frag_chain.last_frag = text_section->frag_chain.first_frag = frag_alloc (); - text_section->frag_chain.last_fixup = text_section->frag_chain.first_fixup = 0; + section_set_flags (text_section, SECTION_FLAG_LOAD | SECTION_FLAG_ALLOC | SECTION_FLAG_READONLY | SECTION_FLAG_CODE); data_section = section_set_by_name (".data"); - data_section->frag_chain.last_frag = data_section->frag_chain.first_frag = frag_alloc (); - data_section->frag_chain.last_fixup = data_section->frag_chain.first_fixup = 0; + section_set_flags (data_section, SECTION_FLAG_LOAD | SECTION_FLAG_ALLOC | SECTION_FLAG_DATA); bss_section = section_set_by_name (".bss"); - bss_section->frag_chain.last_frag = bss_section->frag_chain.first_frag = frag_alloc (); - bss_section->frag_chain.last_fixup = bss_section->frag_chain.first_fixup = 0; + section_set_flags (bss_section, SECTION_FLAG_ALLOC); /* .text section is the default section. */ section_set (text_section); @@ -137,3 +210,21 @@ void sections_init (void) { } #undef CREATE_INTERNAL_SECTION + +void section_set_object_format_dependent_data (struct section *section, void *data) { + section->object_format_dependent_data = data; +} + +void sections_number (unsigned int start_at) { + + struct section *section; + + for (section = sections; section; section = section->next) { + section->number = start_at++; + } + +} + +void *section_get_object_format_dependent_data (struct section *section) { + return section->object_format_dependent_data; +} diff --git a/section.h b/section.h index d4faeaa..cce2903 100644 --- a/section.h +++ b/section.h @@ -4,15 +4,34 @@ #ifndef _SECTION_H #define _SECTION_H +#include + struct frag_chain { struct fixup *first_fixup, *last_fixup; struct frag *first_frag, *last_frag; + unsigned long subsection; struct frag_chain *next; }; +#define SECTION_FLAG_ALLOC (1U << 0) +#define SECTION_FLAG_LOAD (1U << 1) +#define SECTION_FLAG_READONLY (1U << 2) +#define SECTION_FLAG_CODE (1U << 3) +#define SECTION_FLAG_DATA (1U << 4) +#define SECTION_FLAG_NEVER_LOAD (1U << 5) +#define SECTION_FLAG_DEBUGGING (1U << 6) +#define SECTION_FLAG_EXCLUDE (1U << 7) +#define SECTION_FLAG_NOREAD (1U << 8) +#define SECTION_FLAG_SHARED (1U << 9) +#define SECTION_FLAG_LINK_ONCE (1U << 10) +#define SECTION_FLAG_LINK_DUPLICATES_DISCARD (1U << 11) +#define SECTION_FLAG_LINK_DUPLICATES_ONE_ONLY (1U << 12) +#define SECTION_FLAG_LINK_DUPLICATES_SAME_SIZE (1U << 13) +#define SECTION_FLAG_LINK_DUPLICATES_SAME_CONTENTS (1U << 14) + #define SECTION_IS_NORMAL(section) \ ((section != undefined_section) && (section != absolute_section) && (section != expr_section) && (section != reg_section)) @@ -37,6 +56,16 @@ struct section *section_set_by_name (const char *name); struct symbol *section_symbol (struct section *section); const char *section_get_name (struct section *section); -void section_record_alignment_power (struct section *section, int alignment_power); +unsigned int section_get_number (struct section *section); +unsigned int sections_get_count (void); + +unsigned long section_get_flags (struct section *section); +unsigned long section_write_frag_chain (FILE *outfile); + +void section_set_object_format_dependent_data (struct section *section, void *data); +void section_set_flags (struct section *section, unsigned long flags); + +void sections_number (unsigned int start_at); +void *section_get_object_format_dependent_data (struct section *section); #endif /* _SECTION_H */ diff --git a/symbol.c b/symbol.c index 4cc341c..c857281 100644 --- a/symbol.c +++ b/symbol.c @@ -370,6 +370,10 @@ int symbol_uses_reloc_symbol (struct symbol *symbol) { return (symbol->value.type == EXPR_TYPE_SYMBOL && ((symbol_is_resolved (symbol) && symbol->value.op_symbol) || symbol_is_undefined (symbol))); } +unsigned long symbol_get_symbol_table_index (struct symbol *symbol) { + return symbol->symbol_table_index; +} + unsigned long symbol_get_value (struct symbol *symbol) { return symbol_resolve_value (symbol); } @@ -776,6 +780,10 @@ void symbol_set_section (struct symbol *symbol, struct section *section) { symbol->section = section; } +void symbol_set_symbol_table_index (struct symbol *symbol, unsigned long index) { + symbol->symbol_table_index = index; +} + void symbol_set_value (struct symbol *symbol, unsigned long value) { symbol->value.type = EXPR_TYPE_CONSTANT; diff --git a/symbol.h b/symbol.h index 3c5760e..9fdde01 100644 --- a/symbol.h +++ b/symbol.h @@ -18,9 +18,11 @@ struct symbol { struct frag *frag; struct expr value; - int flags; + int resolved, resolving, flags; + + unsigned long symbol_table_index; + int write_name_to_string_table; - int resolved, resolving; struct symbol *next; }; @@ -56,6 +58,7 @@ int symbol_is_undefined (struct symbol *symbol); int symbol_uses_other_symbol (struct symbol *symbol); int symbol_uses_reloc_symbol (struct symbol *symbol); +unsigned long symbol_get_symbol_table_index (struct symbol *symbol); unsigned long symbol_get_value (struct symbol *symbol); unsigned long symbol_resolve_value (struct symbol *symbol); @@ -63,6 +66,7 @@ void symbol_add_to_chain (struct symbol *symbol); void symbol_set_frag (struct symbol *symbol, struct frag *frag); void symbol_set_external (struct symbol *symbol); void symbol_set_section (struct symbol *symbol, struct section *section); +void symbol_set_symbol_table_index (struct symbol *symbol, unsigned long index); void symbol_set_value (struct symbol *symbol, unsigned long value); void symbol_set_value_expression (struct symbol *symbol, struct expr *expr);