---
.gitignore | 1 +
Makefile | 4 +-
include/linker.h | 1 +
include/plan9.h | 2 +
linker/plan9.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++
scas.c | 3 ++
6 files changed, 146 insertions(+), 2 deletions(-)
create mode 100644 include/plan9.h
create mode 100644 linker/plan9.c
diff --git a/.gitignore b/.gitignore
index 00ae34f..e5850b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
*.swp
*.o
+*.6
bin/
*.rom
test/
diff --git a/Makefile b/Makefile
index fd28234..142739f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CFLAGS=-Iinclude/ -O2 -Ibin/ -Wall -Wextra -pedantic -std=c99 -D_XOPEN_SOURCE=70
ASSEMBLER=assembler/privatize.c assembler/directives.c assembler/assembler.c
COMMON=bin/amd64.c bin/z80.c bin/arm64.c common/functions.c common/hashtable.c common/expression.c common/list.c common/operators.c common/runtime.c common/stringop.c common/errors.c common/stack.c common/format.c common/instructions.c common/log.c common/match.c common/md5.c common/objects.c common/readline.c
-LINKER=linker/8xp.c linker/bin.c linker/linker.c linker/merge.c
+LINKER=linker/8xp.c linker/plan9.c linker/bin.c linker/linker.c linker/merge.c
SOURCES=$(ASSEMBLER) $(COMMON) $(LINKER)
all:bin/scas bin/scdump bin/scwrap
@@ -70,7 +70,7 @@ bin/generate_tables: tables/generate.c
mkdir -p bin/
$(CC) $(CFLAGS) $< -o $@
-$(SOURCES:.c=.o) scas.o: bin/z80.h bin/amd64.h bin/arm64.h include/linker.h include/match.h include/format.h include/merge.h include/list.h include/assembler.h include/md5.h include/objects.h include/8xp.h include/stack.h include/bin.h include/directives.h include/errors.h include/instructions.h include/readline.h include/runtime.h include/stringop.h include/hashtable.h include/functions.h include/log.h include/expression.h include/privatize.h include/operators.h
+$(SOURCES:.c=.o) scas.o: bin/z80.h bin/amd64.h bin/arm64.h include/linker.h include/match.h include/format.h include/merge.h include/list.h include/assembler.h include/md5.h include/objects.h include/8xp.h include/plan9.h include/stack.h include/bin.h include/directives.h include/errors.h include/instructions.h include/readline.h include/runtime.h include/stringop.h include/hashtable.h include/functions.h include/log.h include/expression.h include/privatize.h include/operators.h
.c.o:
$(CC) $(CFLAGS) -c $< -o $@
diff --git a/include/linker.h b/include/linker.h
index e6fa184..dfc4bfb 100644
--- a/include/linker.h
+++ b/include/linker.h
@@ -9,4 +9,5 @@ struct linker_settings {
format_writer write_output;
};
+list_t *symbols_gather(list_t *areas, list_t *errors);
void link_objects(FILE *output, list_t *objects, linker_settings_t *settings);
diff --git a/include/plan9.h b/include/plan9.h
new file mode 100644
index 0000000..7686da8
--- /dev/null
+++ b/include/plan9.h
@@ -0,0 +1,2 @@
+int output_plan9(FILE *f, object_t *object, linker_settings_t *settings);
+
diff --git a/linker/plan9.c b/linker/plan9.c
new file mode 100644
index 0000000..6a14171
--- /dev/null
+++ b/linker/plan9.c
@@ -0,0 +1,137 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include "list.h"
+#include "stack.h"
+#include "expression.h"
+#include "objects.h"
+#include "linker.h"
+#include "plan9.h"
+#include "instructions.h"
+#include "runtime.h"
+#include "log.h"
+
+#define HDR_MAGIC 0x00008000 /* header expansion */
+
+#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
+#define A_MAGIC _MAGIC(0, 8) /* 68020 */
+#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
+#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
+#define K_MAGIC _MAGIC(0, 13) /* sparc */
+#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
+#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
+#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
+#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
+#define E_MAGIC _MAGIC(0, 20) /* arm */
+#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
+#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
+#define L_MAGIC _MAGIC(0, 23) /* dec alpha (retired) */
+#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
+#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
+#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
+#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
+#define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */
+
+void write_be32(FILE *f, uint32_t value) {
+ uint8_t bytes[4];
+ bytes[0] = (value >> 24) & 0xff;
+ bytes[1] = (value >> 16) & 0xff;
+ bytes[2] = (value >> 8) & 0xff;
+ bytes[3] = (value) & 0xff;
+ fwrite(bytes, 4, 1, f);
+}
+void write_be64(FILE *f, uint64_t value) {
+ write_be32(f, (value >> 32) & 0xffffffff);
+ write_be32(f, (value) & 0xffffffff);
+}
+
+// returns 1 on failure
+uint32_t get_magic(char* arch) {
+ if (strcmp(arch, "amd64")) {
+ return S_MAGIC;
+ }
+ if (strcmp(arch, "arm64")) {
+ return R_MAGIC;
+ }
+ return 1;
+}
+
+int output_plan9(FILE *f, object_t *object, linker_settings_t *settings) {
+ area_t* data = 0;
+ area_t* text = 0;
+ uint32_t bss_len = 0;
+ uint32_t syms_len = 0;
+ uint64_t entry = 0;
+
+ for (unsigned int i = 0; i < object->areas->length; i++){
+ area_t* area = object->areas->items[i];
+ if (strcmp("_CODE", area->name) == 0) {
+ text = area;
+ relocate_area(text, 0x200028, true);
+ } else if (strcmp("_DATA", area->name) == 0) {
+ data = area;
+ relocate_area(data, 0x400000, true);
+ } else {
+ scas_log(L_ERROR, "unknown section name for plan9 a.out format: %s", area->name);
+ return 1;
+ }
+ }
+ if (text == 0) {
+ scas_log(L_ERROR, "plan9 a.out format needs text section");
+ return 1;
+ }
+
+ // the header
+ uint32_t magic = get_magic(scas_runtime.arch);
+ bool is64 = (magic & HDR_MAGIC) >> 15 == 1;
+ if (magic == 1) return 1;
+ write_be32(f, magic);
+ write_be32(f, text->data_length);
+ if (data != 0)
+ write_be32(f, data->data_length);
+ else
+ write_be32(f, 0);
+ write_be32(f, bss_len);
+ write_be32(f, syms_len);
+ write_be32(f, entry);
+ write_be32(f, 0); // size of pc/sp offset table
+ write_be32(f, 0); // size of pc/line number table
+ if (is64)
+ write_be64(f, entry);
+
+ // write the text
+ fwrite(text->data, 1, text->data_length, f);
+ // write the data (if there is any)
+ if (data != 0)
+ fwrite(data->data, 1, data->data_length, f);
+ // write the symbols
+ uint32_t symseclen = 0;
+ list_t* symbols = symbols_gather(object->areas, settings->errors);
+ for (unsigned int i = 0; i < symbols->length; i++){
+ symbol_t* s = symbols->items[i];
+ if (is64)
+ write_be64(f, s->value);
+ else
+ write_be32(f, s->value);
+ fputc('T' | 0x80, f); // TODO actual type not just text
+ int namelen = strlen(s->name) + 1;
+ fwrite(s->name, sizeof(char), namelen, f);
+ if (strcmp("start", s->name) == 0)
+ entry = s->value;
+ symseclen += 8 + 1 + namelen;
+ }
+ // write back into the header
+ fseek(f, 4 * 4, SEEK_SET);
+ write_be32(f, symseclen);
+ fseek(f, 5 * 4, SEEK_SET);
+ write_be32(f, entry);
+ if (is64) {
+ fseek(f, 8 * 4, SEEK_SET);
+ write_be64(f, entry);
+ }
+ fseek(f, 0, SEEK_END);
+
+ return 0;
+}
diff --git a/scas.c b/scas.c
index b97a488..b55fd3c 100644
--- a/scas.c
+++ b/scas.c
@@ -18,6 +18,7 @@
#include "linker.h"
#include "assembler.h"
#include "8xp.h"
+#include "plan9.h"
#include "bin.h"
#include "merge.h"
#include "runtime.h"
@@ -164,6 +165,8 @@ bool parse_flag(const char *flag) {
scas_runtime.options.output_format = output_bin;
} else if (strcmp(value, "8xp") == 0){
scas_runtime.options.output_format = output_8xp;
+ } else if (strcmp(value, "plan9") == 0){
+ scas_runtime.options.output_format = output_plan9;
} else {
scas_log(L_ERROR, "Unknown output format %s", value);
return false;
--
2.29.3