diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index 76074eff4c..dd5fb4711b 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -579,7 +579,7 @@ class X64Visitor : public WASMDecoder, void visit_F32Sqrt() { visit_F64Sqrt(); } void gen_x64_bytes() { - emit_elf64_header(m_a, 7U); + emit_elf64_header(m_a); // declare compile-time strings std::string base_memory = " "; /* in wasm backend, memory starts after 4 bytes*/ @@ -589,6 +589,9 @@ class X64Visitor : public WASMDecoder, label_to_str["base_memory"] = base_memory; NO_OF_IMPORTS = imports.size(); + + m_a.align_by_byte(0x1000); + m_a.add_label("text_segment_start"); for (uint32_t idx = 0; idx < type_indices.size(); idx++) { m_a.add_label(exports[idx + 1].name); { @@ -607,14 +610,18 @@ class X64Visitor : public WASMDecoder, } - for (auto &s : label_to_str) { - emit_data_string(m_a, s.first, s.second); - } - for (auto &d : double_consts) { emit_double_const(m_a, d.first, d.second); } + m_a.add_label("text_segment_end"); + + m_a.align_by_byte(0x1000); + m_a.add_label("data_segment_start"); + for (auto &s : label_to_str) { + emit_data_string(m_a, s.first, s.second); + } + for (size_t i = 0; i < globals.size(); i++) { uint32_t tmp_offset = globals[i].insts_start_idx; wasm::read_b8(wasm_bytes, tmp_offset); // read byte for i32/i64/f32/f64.const @@ -644,6 +651,7 @@ class X64Visitor : public WASMDecoder, default: throw CodeGenError("decode_global_section: Unsupport global type"); break; } } + m_a.add_label("data_segment_end"); emit_elf64_footer(m_a); } diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index eadff7b7ba..600239d2d8 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -62,7 +62,6 @@ void emit_elf32_header(X86Assembler &a, uint32_t p_flags) { a.asm_dw_imm16(0); // e_shnum a.asm_dw_imm16(0); // e_shstrndx - a.add_var("ehdrsize", a.pos()-a.get_defined_symbol("ehdr").value); /* Elf32_Phdr */ a.add_label("phdr"); @@ -74,13 +73,16 @@ void emit_elf32_header(X86Assembler &a, uint32_t p_flags) { a.asm_dd_label("filesize"); // p_memsz a.asm_dd_imm32(p_flags); // p_flags a.asm_dd_imm32(0x1000); // p_align + a.add_label("phdr_end"); - a.add_var("phdrsize", a.pos()-a.get_defined_symbol("phdr").value); - a.add_var("e_phoff", a.get_defined_symbol("phdr").value-a.origin()); + a.add_var("ehdrsize", "ehdr", "phdr"); + a.add_var("phdrsize", "phdr", "phdr_end"); + a.add_var("e_phoff", "ehdr", "phdr"); } void emit_elf32_footer(X86Assembler &a) { - a.add_var_size("filesize"); + a.add_label("footer"); + a.add_var("filesize", "ehdr", "footer"); } void emit_exit(X86Assembler &a, const std::string &name, @@ -281,8 +283,8 @@ void emit_print_float(X86Assembler &a, const std::string &name) { /************************* 64-bit functions **************************/ -void emit_elf64_header(X86Assembler &a, uint32_t p_flags) { - /* Elf32_Ehdr */ +void emit_elf64_header(X86Assembler &a) { + /* Elf64_Ehdr */ a.add_label("ehdr"); // e_ident a.asm_db_imm8(0x7F); @@ -313,30 +315,54 @@ void emit_elf64_header(X86Assembler &a, uint32_t p_flags) { a.asm_dd_imm32(0); // e_flags a.asm_dw_label("ehdrsize"); // e_ehsize a.asm_dw_label("phdrsize"); // e_phentsize - a.asm_dw_imm16(1); // e_phnum + a.asm_dw_imm16(3); // e_phnum a.asm_dw_imm16(0); // e_shentsize a.asm_dw_imm16(0); // e_shnum a.asm_dw_imm16(0); // e_shstrndx - a.add_var("ehdrsize", a.pos()-a.get_defined_symbol("ehdr").value); - - /* Elf32_Phdr */ + /* Elf64_Phdr */ a.add_label("phdr"); - a.asm_dd_imm32(1); // p_type - a.asm_dd_imm32(p_flags); // p_flags + a.asm_dd_imm32(1); // p_type + a.asm_dd_imm32(4); // p_flags (permission to read only) a.asm_dq_imm64(0); // p_offset a.asm_dq_imm64(a.origin()); // p_vaddr a.asm_dq_imm64(a.origin()); // p_paddr - a.asm_dq_label("filesize"); // p_filesz - a.asm_dq_label("filesize"); // p_memsz + a.asm_dq_label("phdr_size"); // p_filesz + a.asm_dq_label("phdr_size"); // p_memsz a.asm_dq_imm64(0x1000); // p_align - a.add_var("phdrsize", a.pos()-a.get_defined_symbol("phdr").value); - a.add_var64("e_phoff", a.get_defined_symbol("phdr").value-a.origin()); + /* text_segment_phdr */ + a.add_label("text_phdr"); + a.asm_dd_imm32(1); // p_type + a.asm_dd_imm32(5); // p_flags (permission to read and execute) + a.asm_dq_label("text_segment_offset"); // p_offset + a.asm_dq_label("text_segment_start"); // p_vaddr + a.asm_dq_label("text_segment_start"); // p_paddr + a.asm_dq_label("text_segment_size"); // p_filesz + a.asm_dq_label("text_segment_size"); // p_memsz + a.asm_dq_imm64(0x1000); // p_align + + /* data_segment_phdr */ + a.add_label("data_phdr"); + a.asm_dd_imm32(1); // p_type + a.asm_dd_imm32(6); // p_flags (permission to read and write) + a.asm_dq_label("data_segment_offset"); // p_offset + a.asm_dq_label("data_segment_start"); // p_vaddr + a.asm_dq_label("data_segment_start"); // p_paddr + a.asm_dq_label("data_segment_size"); // p_filesz + a.asm_dq_label("data_segment_size"); // p_memsz + a.asm_dq_imm64(0x1000); // p_align } void emit_elf64_footer(X86Assembler &a) { - a.add_var_size("filesize"); + a.add_var("ehdrsize", "ehdr", "phdr"); + a.add_var("phdrsize", "phdr", "text_phdr"); + a.add_var64("e_phoff", "ehdr", "phdr"); + a.add_var64("phdr_size", "ehdr", "text_segment_start"); + a.add_var64("text_segment_offset", "ehdr", "text_segment_start"); + a.add_var64("text_segment_size", "text_segment_start", "text_segment_end"); + a.add_var64("data_segment_offset", "ehdr", "data_segment_start"); + a.add_var64("data_segment_size", "data_segment_start", "data_segment_end"); } void emit_exit_64(X86Assembler &a, std::string name, int exit_code) { diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 8cf73a4b09..8f21f3a7f2 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -30,6 +30,7 @@ Old Link: https://www.systutorials.com/go/intel-x86-64-reference-manual/ #include #include #include +#include #include #include @@ -40,13 +41,11 @@ Old Link: https://www.systutorials.com/go/intel-x86-64-reference-manual/ #ifdef LFORTRAN_ASM_PRINT # define EMIT(s) emit(" ", s) # define EMIT_LABEL(s) emit("", s) -# define EMIT_VAR(a, b) emit("\n", a + " equ " + i2s(b) + "\n") -# define EMIT_VAR_SIZE(a) emit("\n", a + " equ $ - $$\n") // $ is current addr, $$ is start addr +# define EMIT_VAR(a, b, c) emit(" ", a + " equ " + c + " - " + b) #else # define EMIT(s) # define EMIT_LABEL(s) # define EMIT_VAR(a, b) -# define EMIT_VAR_SIZE(a) #endif namespace LCompilers { @@ -465,6 +464,15 @@ class X86Assembler { return m_code; } + void align_by_byte(uint64_t alignment) { + uint64_t code_size = m_code.size() ; + uint64_t padding_size = (alignment * ceil(code_size / (double)alignment)) - code_size; + for (size_t i = 0; i < padding_size; i++) { + m_code.push_back(m_al, 0); + } + EMIT("\n\talign " + std::to_string(alignment) + ", db 0"); + } + void define_symbol(const std::string &name, uint32_t value) { if (m_symbols.find(name) == m_symbols.end()) { Symbol s; @@ -548,22 +556,17 @@ class X86Assembler { EMIT_LABEL(label + ":"); } - void add_var_size(const std::string &var) { - uint64_t val = pos() - origin(); - // TODO: Support 64-bit or 8 byte parameter val in define_symbol() - define_symbol(var, val); - EMIT_VAR_SIZE(var); - } - - void add_var64(const std::string &var, uint64_t val) { + void add_var64(const std::string &var, const std::string &start, const std::string &end) { // TODO: Support 64-bit or 8 byte parameter val in define_symbol() + uint64_t val = get_defined_symbol(end).value - get_defined_symbol(start).value; define_symbol(var, val); - EMIT_VAR(var, val); + EMIT_VAR(var, start, end); } - void add_var(const std::string &var, uint32_t val) { + void add_var(const std::string &var, const std::string &start, const std::string &end) { + uint32_t val = get_defined_symbol(end).value - get_defined_symbol(start).value; define_symbol(var, val); - EMIT_VAR(var, val); + EMIT_VAR(var, start, end); } uint32_t pos() { @@ -1539,7 +1542,7 @@ void emit_print_float(X86Assembler &a, const std::string &name); // Generate an ELF 64 bit header and footer // With these two functions, one only must generate a `_start` assembly // function to have a working binary on Linux. -void emit_elf64_header(X86Assembler &a, uint32_t p_flags=5); +void emit_elf64_header(X86Assembler &a); void emit_elf64_footer(X86Assembler &a); void emit_exit_64(X86Assembler &a, std::string label, int exit_code); diff --git a/src/lpython/tests/test_asm.cpp b/src/lpython/tests/test_asm.cpp index a65010f256..1f1b5601dd 100644 --- a/src/lpython/tests/test_asm.cpp +++ b/src/lpython/tests/test_asm.cpp @@ -403,9 +403,6 @@ BITS 32 dw 0x0000 dw 0x0000 dw 0x0000 - -ehdrsize equ 0x00000034 - phdr: dd 0x00000001 dd 0x00000000 @@ -415,12 +412,10 @@ ehdrsize equ 0x00000034 dd filesize dd 0x00000005 dd 0x00001000 - -phdrsize equ 0x00000020 - - -e_phoff equ 0x00000034 - +phdr_end: + ehdrsize equ phdr - ehdr + phdrsize equ phdr_end - phdr + e_phoff equ phdr - ehdr msg: db 0x48 db 0x65 @@ -446,9 +441,8 @@ e_phoff equ 0x00000034 mov eax, 0x00000001 mov ebx, 0x00000000 int 0x80 - -filesize equ $ - $$ - +footer: + filesize equ footer - ehdr )"""); CHECK(asm_code == ref); #endif