diff --git a/.gitignore b/.gitignore index dc03131..854de3e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build/ .cache/ tags *.o +*.out diff --git a/meson.build b/meson.build index 1bb3fe7..5604ac5 100644 --- a/meson.build +++ b/meson.build @@ -38,3 +38,13 @@ test( depends: [bin], workdir: meson.project_source_root() / 'tests/STB_GLOBAL_NOCONFLICT' ) + +test( + 'et_rel_fail', + find_program('python3'), + args : [ + files('tests/ET_REL_FAIL/tester.py'), bin + ], + depends: [bin], + workdir: meson.project_source_root() / 'tests/ET_REL_FAIL' +) diff --git a/src/link.c b/src/link.c index 57ebb7b..315e112 100644 --- a/src/link.c +++ b/src/link.c @@ -9,6 +9,10 @@ bool shared_emachine(uint64_t base, uint64_t input) { return base == input; } +bool etype_is_et_rel(Elf_header *header) { + return header->e_type == ET_REL; +} + // checks for stb_global symbol collision between files. // drains the symtab hashmap and inserts into global hashmap // collisions between equal values will crash @@ -42,6 +46,7 @@ void stb_global_collision(Hashmap **file_symbols, Hashmap **globals, Objdata *fi // for linking to succeed: // // TODO: +// - [ ] all files are relocatable (eheader->e_type is et_rel) // - [x] same e_machine // - [x] ensure no global bindings are shared between files // undefined external references (every symbol needs to have a corresponding address) @@ -61,6 +66,9 @@ void validate_objmeta(Objdata *head, Args args) { if (!shared_emachine(shared_machine, eheader.e_machine)) fatal_error("Different e_machine detected"); + if (!etype_is_et_rel(&eheader)) + fatal_error("File's e_type is not ET_REL"); + // we get a copy of allocated symtab because stb_global calls hashmap_pop // which modifies the hashmap. Hashmap **symtab_dup = grab_symbol_table(eheader, sheader, args, path); diff --git a/tests/ET_REL_FAIL/makefile b/tests/ET_REL_FAIL/makefile new file mode 100644 index 0000000..e62a124 --- /dev/null +++ b/tests/ET_REL_FAIL/makefile @@ -0,0 +1,7 @@ +clean: + rm *.out + +all: + gcc program1.c -o p1.out + gcc program2.c -o p2.out + gcc program3.c -o p3.out diff --git a/tests/ET_REL_FAIL/program1.c b/tests/ET_REL_FAIL/program1.c new file mode 100644 index 0000000..7ef391c --- /dev/null +++ b/tests/ET_REL_FAIL/program1.c @@ -0,0 +1,5 @@ +#include + +int main() { + printf("hi meow\n"); +} diff --git a/tests/ET_REL_FAIL/program2.c b/tests/ET_REL_FAIL/program2.c new file mode 100644 index 0000000..7ef391c --- /dev/null +++ b/tests/ET_REL_FAIL/program2.c @@ -0,0 +1,5 @@ +#include + +int main() { + printf("hi meow\n"); +} diff --git a/tests/ET_REL_FAIL/program3.c b/tests/ET_REL_FAIL/program3.c new file mode 100644 index 0000000..7ef391c --- /dev/null +++ b/tests/ET_REL_FAIL/program3.c @@ -0,0 +1,5 @@ +#include + +int main() { + printf("hi meow\n"); +} diff --git a/tests/ET_REL_FAIL/tester.py b/tests/ET_REL_FAIL/tester.py new file mode 100755 index 0000000..a22de22 --- /dev/null +++ b/tests/ET_REL_FAIL/tester.py @@ -0,0 +1,42 @@ +#!/bin/python3 + +import subprocess +import os +import sys + +linker_bin = sys.argv[1] + +def test_prom(prom_path: str, bin_path: str, cwd: str): + result = subprocess.run( + [prom_path, bin_path], + capture_output=True, text=True, + cwd=cwd + ) + if result.returncode == 0: + print(f"failed to identify {bin_path} is not ET_REL") + print(result.stdout) + print(result.stderr) + exit(1) + + +def main(): + cwd = os.path.dirname(os.path.abspath(__file__)) + + result = subprocess.run( + ["make", "all", "-C", cwd], + capture_output = True, text = True + ) + + if result.returncode != 0: + print("make failed:", result.stderr) + sys.exit(1) + + # checking prom against binaries + + for i in range(1,4): + test_prom(linker_bin, f"program{i}.out", cwd) + + print("pass") + + +main()