Skip to content

WASM_X64: Support Data Segment #1585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/libasr/codegen/wasm_to_x64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
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*/
Expand All @@ -589,6 +589,9 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
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);
{
Expand All @@ -607,14 +610,18 @@ class X64Visitor : public WASMDecoder<X64Visitor>,

}

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
Expand Down Expand Up @@ -644,6 +651,7 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
default: throw CodeGenError("decode_global_section: Unsupport global type"); break;
}
}
m_a.add_label("data_segment_end");

emit_elf64_footer(m_a);
}
Expand Down
60 changes: 43 additions & 17 deletions src/libasr/codegen/x86_assembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
33 changes: 18 additions & 15 deletions src/libasr/codegen/x86_assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Old Link: https://www.systutorials.com/go/intel-x86-64-reference-manual/
#include <sstream>
#include <fstream>
#include <map>
#include <cmath>

#include <libasr/alloc.h>
#include <libasr/containers.h>
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 6 additions & 12 deletions src/lpython/tests/test_asm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,6 @@ BITS 32
dw 0x0000
dw 0x0000
dw 0x0000

ehdrsize equ 0x00000034

phdr:
dd 0x00000001
dd 0x00000000
Expand All @@ -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
Expand All @@ -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
Expand Down