def assemble(argv=None): """Assembles an ELFHex source program into an executable, with the provided arguments taken from the command line by default. """ # Parse arguments. args = _parse_args(argv) # Preprocess source (resolves includes and fragment references). preprocessed = elfhex.Preprocessor(elfhex.FileLoader( args.include_path)).preprocess(args.input_path, args.max_fragment_depth) # Transform the syntax into a Program instance. program = elfhex.Transformer().transform(preprocessed) if not args.no_header: # Add the ELF header. header = elfhex.elf.get_header(args.entry_label) if args.header_segment: program.prepend_header_segment(header) else: program.prepend_header_to_first_segment(header) # Generate the binary output. output = program.render(args.memory_start) # Output the resulting blob. open(args.output_path, "wb").write(output) _set_executable(args.output_path) print(f"Assembled. Total size: {len(output)} bytes.")
def test_preprocessor_incompatiblemetadata(): files = { MAIN_FILE: 'program 3 < 4096 include "other.eh" ' + _segment(""), "other.eh": "program 2 < 4096", } with pytest.raises(elfhex.ElfhexError): elfhex.Preprocessor(files).preprocess(MAIN_FILE, 1) files = { MAIN_FILE: 'program 3 < 4096 include "other.eh" ' + _segment(""), "other.eh": "program 3 > 4096", } with pytest.raises(elfhex.ElfhexError): elfhex.Preprocessor(files).preprocess(MAIN_FILE, 1)
def test_preprocessor_includeonce(): files = { MAIN_FILE: f'{METADATA} include "other.eh" {_segment("")}', "other.eh": f'{METADATA} include "{MAIN_FILE}"', } elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2)
def test_preprocessor_uniqueref(): files = { MAIN_FILE: METADATA + _segment("@!a() @!a() @a()") + " fragment a() { 00 }" } output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2) assert output == _flattened("00 00")
def test_preprocessor_maxrecursion(): files = { MAIN_FILE: METADATA + _segment("@a()") + " fragment a() { @b() } fragment b() { @c() } fragment c() { ff }" } with pytest.raises(elfhex.ElfhexError): elfhex.Preprocessor(files).preprocess(MAIN_FILE, 0)
def test_preprocessor_fragmentsonly(): files = { MAIN_FILE: f'{METADATA} include fragments "other.eh" {_segment("ff @f()")}', "other.eh": METADATA + "segment a() { ee } fragment f() { 11 }", } output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2) assert output == _flattened("ff 11")
def test_preprocessor_extendalign(): files = { MAIN_FILE: 'program 3 < 16 include "other.eh" ' + _segment(""), "other.eh": "program 3 < 32", } output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 1) assert output == _flattened("", metadata="program 3 < 32")
def test_preprocessor_fragments(): files = { MAIN_FILE: METADATA + _segment("ff @a(11)") + "fragment a(a) { $a @b($a) } fragment b(a) { $a }" } output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 3) assert output == _flattened("ff 11 11")
def test_preprocessor_locallabels(): files = {MAIN_FILE: METADATA + _segment("@a()") + " fragment a() { [__a] }"} output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2) assert output == _flattened("[__0__a]")
def test_preprocessor_aliases(): files = {MAIN_FILE: METADATA + _segment("@a()(test)") + " fragment a() { [a] }"} output = elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2) assert output == _flattened("[test.a]")
def test_preprocessor_invalidfragmentdepth(): with pytest.raises(ValueError): elfhex.Preprocessor({}).preprocess(MAIN_FILE, -1)
def test_preprocessor_nofragment(): files = {MAIN_FILE: METADATA + _segment("@!b()") + " fragment a() { 00 }"} with pytest.raises(elfhex.ElfhexError): elfhex.Preprocessor(files).preprocess(MAIN_FILE, 2)