From b766d8a782060500e6c2da2ca02f9e7124b53a02 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Mon, 10 Apr 2023 23:53:45 +0530 Subject: [PATCH 01/11] X64: Define elf ehdr, phdr structs for x86 and x64 --- src/libasr/codegen/x86_assembler.cpp | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index 600239d2d8..2db959965c 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -25,6 +25,36 @@ void X86Assembler::save_binary(const std::string &filename) { #endif } +// ELF header structure for 32-bit +struct Elf32_Ehdr { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t phoff; + uint32_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +// Program header structure for 32-bit +struct Elf32_Phdr { + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filesz; + uint32_t memsz; + uint32_t flags; + uint32_t align; +}; + void emit_elf32_header(X86Assembler &a, uint32_t p_flags) { /* Elf32_Ehdr */ a.add_label("ehdr"); @@ -283,6 +313,37 @@ void emit_print_float(X86Assembler &a, const std::string &name) { /************************* 64-bit functions **************************/ +// ELF header structure for 64-bit +struct Elf64_Ehdr { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry; + uint64_t phoff; + uint64_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +// Program header structure for 64-bit +struct Elf64_Phdr { + uint32_t type; + uint32_t flags; + uint64_t offset; + uint64_t vaddr; + uint64_t paddr; + uint64_t filesz; + uint64_t memsz; + uint64_t align; +}; + + void emit_elf64_header(X86Assembler &a) { /* Elf64_Ehdr */ a.add_label("ehdr"); From dab6068e179b96a32bceaad8811eac47b9637fb7 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Tue, 11 Apr 2023 00:17:56 +0530 Subject: [PATCH 02/11] X64: Define header constructing functions --- src/libasr/codegen/wasm_to_x64.cpp | 5 - src/libasr/codegen/x86_assembler.cpp | 141 ++++++++++++++++++++++++++- src/libasr/codegen/x86_assembler.h | 5 + 3 files changed, 145 insertions(+), 6 deletions(-) diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index af048265d2..076b93bfe9 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -581,8 +581,6 @@ class X64Visitor : public WASMDecoder, void visit_F32Sqrt() { visit_F64Sqrt(); } void gen_x64_bytes() { - emit_elf64_header(m_a); - // declare compile-time strings std::string base_memory = " "; /* in wasm backend, memory starts after 4 bytes*/ for (uint32_t i = 0; i < data_segments.size(); i++) { @@ -592,7 +590,6 @@ class X64Visitor : public WASMDecoder, 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); @@ -647,8 +644,6 @@ class X64Visitor : public WASMDecoder, } } 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 2db959965c..8f8f95f8ce 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -11,10 +11,11 @@ namespace LCompilers { void X86Assembler::save_binary(const std::string &filename) { + Vec bin = create_elf64_x86_binary(m_al, *this); { std::ofstream out; out.open(filename); - out.write((const char*) m_code.p, m_code.size()); + out.write((const char*) bin.p, bin.size()); } #ifdef LFORTRAN_LINUX std::string mode = "0755"; @@ -343,6 +344,144 @@ struct Elf64_Phdr { uint64_t align; }; +Elf64_Ehdr get_elf_header(uint64_t asm_entry) { + Elf64_Ehdr e; + e.ident[0] = 0x7f; // magic number + e.ident[1] = 'E'; + e.ident[2] = 'L'; + e.ident[3] = 'F'; + e.ident[4] = 2; // file class (64-bit) + e.ident[5] = 1; // data encoding (little endian) + e.ident[6] = 1; // ELF version + e.ident[7] = 0; // padding + e.ident[8] = 0; + e.ident[9] = 0; + e.ident[10] = 0; + e.ident[11] = 0; + e.ident[12] = 0; + e.ident[13] = 0; + e.ident[14] = 0; + e.ident[15] = 0; + e.type = 2; + e.machine = 0x3e; + e.version = 1; + e.entry = asm_entry; + e.phoff = sizeof(Elf64_Ehdr); + e.shoff = 0; + e.flags = 0; + e.ehsize = sizeof(Elf64_Ehdr); + e.phentsize = sizeof(Elf64_Phdr); + e.phnum = 3; + e.shentsize = 0; + e.shnum = 0; + e.shstrndx = 0; + return e; +} + +Elf64_Phdr get_program_header(uint64_t addr_origin, uint64_t seg_size) { + Elf64_Phdr p; + p.type = 1; + p.flags = 4; + p.offset = 0; + p.vaddr = addr_origin; + p.paddr = p.vaddr; + p.filesz = seg_size; + p.memsz = p.filesz; + p.align = 0x1000; + return p; +} + +Elf64_Phdr get_text_segment(uint64_t addr_origin, uint64_t prev_seg_offset, uint64_t prev_seg_size, uint64_t seg_size) { + Elf64_Phdr p; + p.type = 1; + p.flags = 5; + p.offset = prev_seg_offset + prev_seg_size; + p.vaddr = addr_origin + p.offset; + p.paddr = p.vaddr; + p.filesz = seg_size; + p.memsz = p.filesz; + p.align = 0x1000; + return p; +} + +Elf64_Phdr get_data_segment(uint64_t addr_origin, uint64_t prev_seg_offset, uint64_t prev_seg_size, uint64_t seg_size) { + Elf64_Phdr p; + p.type = 1; + p.flags = 6; + p.offset = prev_seg_offset + prev_seg_size; + p.vaddr = addr_origin + p.offset; + p.paddr = p.vaddr; + p.filesz = seg_size; + p.memsz = p.filesz; + p.align = 0x1000; + return p; +} + +template +void append_header_bytes(Allocator &al, T src, Vec &des) { + char *byteArray = (char *)&src; + for (size_t i = 0; i < sizeof(src); i++) { + des.push_back(al, byteArray[i]); + } + } + + +void align_by_byte(Allocator &al, Vec &code, uint64_t alignment) { + uint64_t code_size = code.size() ; + uint64_t padding_size = (alignment * ceil(code_size / (double)alignment)) - code_size; + for (size_t i = 0; i < padding_size; i++) { + code.push_back(al, 0); + } + } + +Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a) { + + /* + The header segment is a segment which holds the elf and program headers. + Its size currently is + sizeof(Elf64_Ehdr) + 3 * sizeof(Elf64_Phdr) + that is, 64 + 3 * 56 = 232 + Since, it is a segment, it needs to be aligned by boundary 0x1000 + (we add temporary zero bytes as padding to accomplish this alignment) + + Thus, the header segment size for us currently is 0x1000. + + For now, we are hardcoding this size here. + + TODO: Later compute this header segment size dynamically depending + on the different segments present + */ + const int HEADER_SEGMENT_SIZE = 0x1000; + + // adjust/offset the origin address as per the extra bytes of HEADER_SEGMENT_SIZE + uint64_t origin_addr = a.origin() - HEADER_SEGMENT_SIZE; + + Elf64_Ehdr e = get_elf_header(a.get_defined_symbol("_start").value); + Elf64_Phdr p_program = get_program_header(origin_addr, HEADER_SEGMENT_SIZE); + Elf64_Phdr p_text_seg = get_text_segment(origin_addr, p_program.offset, p_program.filesz, + a.get_defined_symbol("text_segment_end").value - a.get_defined_symbol("text_segment_start").value); + Elf64_Phdr p_data_seg = get_data_segment(origin_addr, p_text_seg.offset, p_text_seg.filesz, + a.get_defined_symbol("data_segment_end").value - a.get_defined_symbol("data_segment_start").value); + + Vec bin; + bin.reserve(al, HEADER_SEGMENT_SIZE); + + { + append_header_bytes(al, e, bin); + append_header_bytes(al, p_program, bin); + append_header_bytes(al, p_text_seg, bin); + append_header_bytes(al, p_data_seg, bin); + + LCompilers::align_by_byte(al, bin, 0x1000); + } + + for (auto b:a.get_machine_code()) { + bin.push_back(al, b); + } + + return bin; +} + void emit_elf64_header(X86Assembler &a) { /* Elf64_Ehdr */ diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 8f21f3a7f2..50c26c5a60 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -1539,6 +1539,11 @@ void emit_print(X86Assembler &a, const std::string &msg_label, void emit_print_int(X86Assembler &a, const std::string &name); void emit_print_float(X86Assembler &a, const std::string &name); +template +void append_header_bytes(Allocator &al, T src, Vec &des); +void align_by_byte(Allocator &al, Vec &code, uint64_t alignment); +Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a); + // 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. From bd19300c01b3531f689b6ece63acc0d9ec6af32a Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Thu, 13 Apr 2023 22:10:44 +0530 Subject: [PATCH 03/11] WASM: X64: Emit alignment bytes before segment end --- src/libasr/codegen/wasm_to_x64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index 076b93bfe9..cbce8fbd6a 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -613,9 +613,9 @@ class X64Visitor : public WASMDecoder, emit_double_const(m_a, d.first, d.second); } + m_a.align_by_byte(0x1000); 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); From a05b71c4fd166106688d89f5a0b7797e49ffeb3c Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Thu, 13 Apr 2023 22:33:51 +0530 Subject: [PATCH 04/11] WASM_X64: Define and use common get_seg_header() --- src/libasr/codegen/x86_assembler.cpp | 45 +++++++--------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index 8f8f95f8ce..f9c4a3fb26 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -378,38 +378,13 @@ Elf64_Ehdr get_elf_header(uint64_t asm_entry) { return e; } -Elf64_Phdr get_program_header(uint64_t addr_origin, uint64_t seg_size) { +Elf64_Phdr get_seg_header(uint32_t flags, uint64_t origin_addr, + uint64_t seg_size, uint64_t prev_seg_offset, uint64_t prev_seg_size) { Elf64_Phdr p; p.type = 1; - p.flags = 4; - p.offset = 0; - p.vaddr = addr_origin; - p.paddr = p.vaddr; - p.filesz = seg_size; - p.memsz = p.filesz; - p.align = 0x1000; - return p; -} - -Elf64_Phdr get_text_segment(uint64_t addr_origin, uint64_t prev_seg_offset, uint64_t prev_seg_size, uint64_t seg_size) { - Elf64_Phdr p; - p.type = 1; - p.flags = 5; + p.flags = flags; p.offset = prev_seg_offset + prev_seg_size; - p.vaddr = addr_origin + p.offset; - p.paddr = p.vaddr; - p.filesz = seg_size; - p.memsz = p.filesz; - p.align = 0x1000; - return p; -} - -Elf64_Phdr get_data_segment(uint64_t addr_origin, uint64_t prev_seg_offset, uint64_t prev_seg_size, uint64_t seg_size) { - Elf64_Phdr p; - p.type = 1; - p.flags = 6; - p.offset = prev_seg_offset + prev_seg_size; - p.vaddr = addr_origin + p.offset; + p.vaddr = origin_addr + p.offset; p.paddr = p.vaddr; p.filesz = seg_size; p.memsz = p.filesz; @@ -457,11 +432,13 @@ Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a) { uint64_t origin_addr = a.origin() - HEADER_SEGMENT_SIZE; Elf64_Ehdr e = get_elf_header(a.get_defined_symbol("_start").value); - Elf64_Phdr p_program = get_program_header(origin_addr, HEADER_SEGMENT_SIZE); - Elf64_Phdr p_text_seg = get_text_segment(origin_addr, p_program.offset, p_program.filesz, - a.get_defined_symbol("text_segment_end").value - a.get_defined_symbol("text_segment_start").value); - Elf64_Phdr p_data_seg = get_data_segment(origin_addr, p_text_seg.offset, p_text_seg.filesz, - a.get_defined_symbol("data_segment_end").value - a.get_defined_symbol("data_segment_start").value); + Elf64_Phdr p_program = get_seg_header(4, origin_addr, HEADER_SEGMENT_SIZE, 0, 0); + + const uint64_t text_seg_size = a.get_defined_symbol("text_segment_end").value - a.get_defined_symbol("text_segment_start").value; + Elf64_Phdr p_text_seg = get_seg_header(5, origin_addr, text_seg_size, p_program.offset, p_program.filesz); + + const uint64_t data_seg_size = a.get_defined_symbol("data_segment_end").value - a.get_defined_symbol("data_segment_start").value; + Elf64_Phdr p_data_seg = get_seg_header(6, origin_addr, data_seg_size, p_text_seg.offset, p_text_seg.filesz); Vec bin; bin.reserve(al, HEADER_SEGMENT_SIZE); From 150a9c89ba7f7885b216a09e411bdbd7708f4fd6 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Thu, 13 Apr 2023 22:20:56 +0530 Subject: [PATCH 05/11] WASM_X64: Support elf headers, footer in asm text --- src/libasr/codegen/x86_assembler.h | 84 ++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 50c26c5a60..1e6ec875de 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -436,8 +436,7 @@ class X86Assembler { m_origin = 0x08048000; #ifdef LFORTRAN_ASM_PRINT if (bits64) { - m_asm_code = "BITS 64\n"; - emit(" ", "org " + i2s((uint64_t)m_origin) + "\n"); // specify origin info + m_asm_code = ""; } else { m_asm_code = "BITS 32\n"; emit(" ", "org " + i2s(m_origin) + "\n"); // specify origin info @@ -447,7 +446,86 @@ class X86Assembler { #ifdef LFORTRAN_ASM_PRINT std::string get_asm() { - return m_asm_code; + + std::string header = +R"(BITS 64 + org )" + i2s((uint64_t) m_origin) + R"( + +ehdr: + db 0x7f + db 0x45 + db 0x4c + db 0x46 + db 0x02 + db 0x01 + db 0x01 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + db 0x00 + dw 0x0002 + dw 0x003e + dd 0x00000001 + dq _start + dq e_phoff + dq 0x0000000000000000 + dd 0x00000000 + dw ehdrsize + dw phdrsize + dw 0x0003 + dw 0x0000 + dw 0x0000 + dw 0x0000 +phdr: + dd 0x00000001 + dd 0x00000004 + dq header_segment_offset + dq header_segment_start + dq header_segment_start + dq header_segment_size + dq header_segment_size + dq 0x0000000000001000 +text_phdr: + dd 0x00000001 + dd 0x00000005 + dq text_segment_offset + dq text_segment_start + dq text_segment_start + dq text_segment_size + dq text_segment_size + dq 0x0000000000001000 +data_phdr: + dd 0x00000001 + dd 0x00000006 + dq data_segment_offset + dq data_segment_start + dq data_segment_start + dq data_segment_size + dq data_segment_size + dq 0x0000000000001000 + + align 4096, db 0 + +)"; + + std::string footer = R"( + ehdrsize equ phdr - ehdr + phdrsize equ text_phdr - phdr + e_phoff equ phdr - ehdr + header_segment_offset equ ehdr - ehdr + header_segment_start equ ehdr + header_segment_size equ text_segment_start - ehdr + text_segment_offset equ text_segment_start - ehdr + text_segment_size equ text_segment_end - text_segment_start + data_segment_offset equ data_segment_start - ehdr + data_segment_size equ data_segment_end - data_segment_start +)"; + return header + m_asm_code + footer; } // Saves the generated assembly into a file From 9ffc308637c56e5438a0028e688df0844b2a0a7d Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Thu, 13 Apr 2023 23:16:40 +0530 Subject: [PATCH 06/11] X86Assembler: Isolate get_asm() and save_bin() for 32 and 64bit --- src/libasr/codegen/wasm_to_x64.cpp | 4 ++-- src/libasr/codegen/x86_assembler.cpp | 17 ++++++++++++++++- src/libasr/codegen/x86_assembler.h | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index cbce8fbd6a..2ffac69ed9 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -695,7 +695,7 @@ Result wasm_to_x64(Vec &wasm_bytes, Allocator &al, { auto t1 = std::chrono::high_resolution_clock::now(); - m_a.save_binary(filename); + m_a.save_binary64(filename); auto t2 = std::chrono::high_resolution_clock::now(); time_save = std::chrono::duration_cast(t2 - t1) @@ -703,7 +703,7 @@ Result wasm_to_x64(Vec &wasm_bytes, Allocator &al, } //! Helpful for debugging - // std::cout << x64_visitor.m_a.get_asm() << std::endl; + // std::cout << x64_visitor.m_a.get_asm64() << std::endl; if (time_report) { std::cout << "Codegen Time report:" << std::endl; diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index f9c4a3fb26..2d07f9baed 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -10,7 +10,7 @@ namespace LCompilers { -void X86Assembler::save_binary(const std::string &filename) { +void X86Assembler::save_binary64(const std::string &filename) { Vec bin = create_elf64_x86_binary(m_al, *this); { std::ofstream out; @@ -26,6 +26,21 @@ void X86Assembler::save_binary(const std::string &filename) { #endif } +void X86Assembler::save_binary(const std::string &filename) { + { + std::ofstream out; + out.open(filename); + out.write((const char*) m_code.p, m_code.size()); + } +#ifdef LFORTRAN_LINUX + std::string mode = "0755"; + int mod = strtol(mode.c_str(), 0, 8); + if (chmod(filename.c_str(),mod) < 0) { + throw AssemblerError("chmod failed"); + } +#endif +} + // ELF header structure for 32-bit struct Elf32_Ehdr { uint8_t ident[16]; diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 1e6ec875de..f5d9e4a9ca 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -446,7 +446,10 @@ class X86Assembler { #ifdef LFORTRAN_ASM_PRINT std::string get_asm() { + return m_asm_code; + } + std::string get_asm64() { std::string header = R"(BITS 64 org )" + i2s((uint64_t) m_origin) + R"( @@ -666,6 +669,7 @@ R"(BITS 64 // Saves the generated machine code into a binary file void save_binary(const std::string &filename); + void save_binary64(const std::string &filename); void asm_pop_r64(X64Reg r64) { X86Reg r32 = X86Reg(r64 & 7); From 06ed809cc93855bbd0b117e8151d3ba487cd0f69 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Wed, 12 Apr 2023 09:21:32 +0530 Subject: [PATCH 07/11] WASM: Fix neg val assign to global_var_idx --- src/libasr/codegen/asr_to_wasm.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index 5f39757010..dd0ed21286 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -526,7 +527,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { using namespace wasm; int kind = ASRUtils::extract_kind_from_ttype_t(v->m_type); - uint32_t global_var_idx = -1; + uint32_t global_var_idx = UINT_MAX; switch (v->m_type->type){ case ASR::ttypeType::Integer: { uint64_t init_val = 0; @@ -583,7 +584,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { global_var_idx = m_wa.declare_global_var(i32, 0); } } - LCOMPILERS_ASSERT(global_var_idx >= 0); + LCOMPILERS_ASSERT(global_var_idx < UINT_MAX); m_global_var_idx_map[get_hash((ASR::asr_t *)v)] = global_var_idx; } From f12e42ccaf9809daaadea9cbb1d2f14da98fdf4b Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Thu, 13 Apr 2023 23:34:51 +0530 Subject: [PATCH 08/11] WASM_X64: Remove unused functions --- src/libasr/codegen/x86_assembler.cpp | 91 ---------------------------- src/libasr/codegen/x86_assembler.h | 11 +--- 2 files changed, 3 insertions(+), 99 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index 2d07f9baed..44ee2a4637 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -474,97 +474,6 @@ Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a) { return bin; } - -void emit_elf64_header(X86Assembler &a) { - /* Elf64_Ehdr */ - a.add_label("ehdr"); - // e_ident - a.asm_db_imm8(0x7F); - a.asm_db_imm8('E'); - a.asm_db_imm8('L'); - a.asm_db_imm8('F'); - a.asm_db_imm8(2); - a.asm_db_imm8(1); - a.asm_db_imm8(1); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - a.asm_db_imm8(0); - - a.asm_dw_imm16(2); // e_type - a.asm_dw_imm16(0x3e); // e_machine - a.asm_dd_imm32(1); // e_version - a.asm_dq_label("_start"); // e_entry - a.asm_dq_label("e_phoff"); // e_phoff - a.asm_dq_imm64(0); // e_shoff - 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(3); // e_phnum - a.asm_dw_imm16(0); // e_shentsize - a.asm_dw_imm16(0); // e_shnum - a.asm_dw_imm16(0); // e_shstrndx - - /* Elf64_Phdr */ - a.add_label("phdr"); - 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("phdr_size"); // p_filesz - a.asm_dq_label("phdr_size"); // p_memsz - a.asm_dq_imm64(0x1000); // p_align - - /* 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("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) { - a.add_label(name); - // void exit(int status); - a.asm_mov_r64_imm64(LCompilers::X64Reg::rax, 60); // sys_exit - a.asm_mov_r64_imm64(LCompilers::X64Reg::rdi, exit_code); // exit code - a.asm_syscall(); // syscall -} - void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size) { // mov rax, 1 ; write( diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index f5d9e4a9ca..b192121841 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -1621,19 +1621,14 @@ void emit_print(X86Assembler &a, const std::string &msg_label, void emit_print_int(X86Assembler &a, const std::string &name); void emit_print_float(X86Assembler &a, const std::string &name); +// Generate an ELF 64 bit header and footer +// With these three functions, one only must generate a `_start` assembly +// function to have a working binary on Linux. template void append_header_bytes(Allocator &al, T src, Vec &des); void align_by_byte(Allocator &al, Vec &code, uint64_t alignment); Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a); -// 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); -void emit_elf64_footer(X86Assembler &a); - -void emit_exit_64(X86Assembler &a, std::string label, int exit_code); - void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size); void emit_print_int_64(X86Assembler &a, const std::string &name); void emit_print_double(X86Assembler &a, const std::string &name); From 14b119739d5755dddf5a4e04918990572f710487 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Fri, 14 Apr 2023 11:50:00 +0530 Subject: [PATCH 09/11] WASM_X64: Create and return only header binary --- src/libasr/codegen/x86_assembler.cpp | 27 ++++++++++++--------------- src/libasr/codegen/x86_assembler.h | 2 +- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index 44ee2a4637..e09633edae 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -11,11 +11,12 @@ namespace LCompilers { void X86Assembler::save_binary64(const std::string &filename) { - Vec bin = create_elf64_x86_binary(m_al, *this); + Vec header = create_elf64_x86_header(m_al, *this); { std::ofstream out; out.open(filename); - out.write((const char*) bin.p, bin.size()); + out.write((const char*) header.p, header.size()); + out.write((const char*) m_code.p, m_code.size()); } #ifdef LFORTRAN_LINUX std::string mode = "0755"; @@ -424,7 +425,7 @@ void align_by_byte(Allocator &al, Vec &code, uint64_t alignment) { } } -Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a) { +Vec create_elf64_x86_header(Allocator &al, X86Assembler &a) { /* The header segment is a segment which holds the elf and program headers. @@ -455,23 +456,19 @@ Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a) { const uint64_t data_seg_size = a.get_defined_symbol("data_segment_end").value - a.get_defined_symbol("data_segment_start").value; Elf64_Phdr p_data_seg = get_seg_header(6, origin_addr, data_seg_size, p_text_seg.offset, p_text_seg.filesz); - Vec bin; - bin.reserve(al, HEADER_SEGMENT_SIZE); + Vec header; + header.reserve(al, HEADER_SEGMENT_SIZE); { - append_header_bytes(al, e, bin); - append_header_bytes(al, p_program, bin); - append_header_bytes(al, p_text_seg, bin); - append_header_bytes(al, p_data_seg, bin); - - LCompilers::align_by_byte(al, bin, 0x1000); - } + append_header_bytes(al, e, header); + append_header_bytes(al, p_program, header); + append_header_bytes(al, p_text_seg, header); + append_header_bytes(al, p_data_seg, header); - for (auto b:a.get_machine_code()) { - bin.push_back(al, b); + LCompilers::align_by_byte(al, header, 0x1000); } - return bin; + return header; } void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size) diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index b192121841..f89ef01169 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -1627,7 +1627,7 @@ void emit_print_float(X86Assembler &a, const std::string &name); template void append_header_bytes(Allocator &al, T src, Vec &des); void align_by_byte(Allocator &al, Vec &code, uint64_t alignment); -Vec create_elf64_x86_binary(Allocator &al, X86Assembler &a); +Vec create_elf64_x86_header(Allocator &al, X86Assembler &a); void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size); void emit_print_int_64(X86Assembler &a, const std::string &name); From 0630d23b5dd2e6c1cfd84fa20617d6929a13405c Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Fri, 14 Apr 2023 11:56:51 +0530 Subject: [PATCH 10/11] WASM_X64: Pass only required params to create_elf64_x86_header() --- src/libasr/codegen/x86_assembler.cpp | 16 ++++++++-------- src/libasr/codegen/x86_assembler.h | 7 ++++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index e09633edae..feea8843a3 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -11,7 +11,10 @@ namespace LCompilers { void X86Assembler::save_binary64(const std::string &filename) { - Vec header = create_elf64_x86_header(m_al, *this); + Vec header = create_elf64_x86_header( + m_al, origin(), get_defined_symbol("_start").value, + compute_seg_size("text_segment_start", "text_segment_end"), + compute_seg_size("data_segment_start", "data_segment_end")); { std::ofstream out; out.open(filename); @@ -425,7 +428,8 @@ void align_by_byte(Allocator &al, Vec &code, uint64_t alignment) { } } -Vec create_elf64_x86_header(Allocator &al, X86Assembler &a) { +Vec create_elf64_x86_header(Allocator &al, uint64_t origin, uint64_t entry, + uint64_t text_seg_size, uint64_t data_seg_size) { /* The header segment is a segment which holds the elf and program headers. @@ -445,15 +449,11 @@ Vec create_elf64_x86_header(Allocator &al, X86Assembler &a) { const int HEADER_SEGMENT_SIZE = 0x1000; // adjust/offset the origin address as per the extra bytes of HEADER_SEGMENT_SIZE - uint64_t origin_addr = a.origin() - HEADER_SEGMENT_SIZE; + uint64_t origin_addr = origin - HEADER_SEGMENT_SIZE; - Elf64_Ehdr e = get_elf_header(a.get_defined_symbol("_start").value); + Elf64_Ehdr e = get_elf_header(entry); Elf64_Phdr p_program = get_seg_header(4, origin_addr, HEADER_SEGMENT_SIZE, 0, 0); - - const uint64_t text_seg_size = a.get_defined_symbol("text_segment_end").value - a.get_defined_symbol("text_segment_start").value; Elf64_Phdr p_text_seg = get_seg_header(5, origin_addr, text_seg_size, p_program.offset, p_program.filesz); - - const uint64_t data_seg_size = a.get_defined_symbol("data_segment_end").value - a.get_defined_symbol("data_segment_start").value; Elf64_Phdr p_data_seg = get_seg_header(6, origin_addr, data_seg_size, p_text_seg.offset, p_text_seg.filesz); Vec header; diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index f89ef01169..bf722c668a 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -554,6 +554,10 @@ R"(BITS 64 EMIT("\n\talign " + std::to_string(alignment) + ", db 0"); } + uint64_t compute_seg_size(std::string start_flag, std::string end_flag) { + return get_defined_symbol(end_flag).value - get_defined_symbol(start_flag).value; + } + void define_symbol(const std::string &name, uint32_t value) { if (m_symbols.find(name) == m_symbols.end()) { Symbol s; @@ -1627,7 +1631,8 @@ void emit_print_float(X86Assembler &a, const std::string &name); template void append_header_bytes(Allocator &al, T src, Vec &des); void align_by_byte(Allocator &al, Vec &code, uint64_t alignment); -Vec create_elf64_x86_header(Allocator &al, X86Assembler &a); +Vec create_elf64_x86_header(Allocator &al, uint64_t origin, uint64_t entry, + uint64_t text_seg_size, uint64_t data_seg_size); void emit_print_64(X86Assembler &a, const std::string &msg_label, uint64_t size); void emit_print_int_64(X86Assembler &a, const std::string &name); From 1a99f9aaeca7cf03467062e57883d885aa54b9e8 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Fri, 14 Apr 2023 20:59:22 +0530 Subject: [PATCH 11/11] WASM_X64: Assign mod value directly as constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Čertík --- src/libasr/codegen/x86_assembler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index feea8843a3..5f82a98f4f 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -22,8 +22,7 @@ void X86Assembler::save_binary64(const std::string &filename) { out.write((const char*) m_code.p, m_code.size()); } #ifdef LFORTRAN_LINUX - std::string mode = "0755"; - int mod = strtol(mode.c_str(), 0, 8); + int mod = 0755; if (chmod(filename.c_str(),mod) < 0) { throw AssemblerError("chmod failed"); }