From 085677bc2b234a1276bce6a62cb37302d7bd10c4 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 18 Jul 2022 15:57:16 +0200 Subject: [PATCH] Syscall* ASTNodes and LLVM IR generation for x86 Inline assembly for the win! --- CMakeLists.txt | 2 + src/AST/SyscallNode.cpp | 258 ++++++++++++++++++++++++++++++++++++++++ src/AST/SyscallNode.h | 86 ++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 src/AST/SyscallNode.cpp create mode 100644 src/AST/SyscallNode.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d14ebab..6d9eea1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,8 @@ add_executable( src/AST/NumberNode.h src/AST/SumNode.cpp src/AST/SumNode.h + src/AST/SyscallNode.cpp + src/AST/SyscallNode.h src/utils.cpp src/utils.h src/Parser.cpp diff --git a/src/AST/SyscallNode.cpp b/src/AST/SyscallNode.cpp new file mode 100644 index 0000000..ea26afe --- /dev/null +++ b/src/AST/SyscallNode.cpp @@ -0,0 +1,258 @@ +#include "SyscallNode.h" +#include "../Arguments.h" +#include "../Error.h" +#include "llvm/IR/InlineAsm.h" + +Syscall0Node::Syscall0Node(int syscall_number) : sys_num(syscall_number), ExprNode() +{ +} + +Syscall0Node::~Syscall0Node() +{ +} + +Syscall1Node::Syscall1Node(int syscall_number, std::shared_ptr arg1) + : sys_num(syscall_number), arg1(arg1), ExprNode() +{ +} + +Syscall1Node::~Syscall1Node() +{ +} + +Syscall2Node::Syscall2Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2) + : sys_num(syscall_number), arg1(arg1), arg2(arg2), ExprNode() +{ +} + +Syscall2Node::~Syscall2Node() +{ +} + +Syscall3Node::Syscall3Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3) + : sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), ExprNode() +{ +} + +Syscall3Node::~Syscall3Node() +{ +} + +Syscall4Node::Syscall4Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3, std::shared_ptr arg4) + : sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), ExprNode() +{ +} + +Syscall4Node::~Syscall4Node() +{ +} + +Syscall5Node::Syscall5Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3, std::shared_ptr arg4, std::shared_ptr arg5) + : sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), ExprNode() +{ +} + +Syscall5Node::~Syscall5Node() +{ +} + +llvm::Value* Syscall0Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} + +llvm::Value* Syscall1Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + arg1->codegen(generator)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80), + arg1->codegen(generator)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} + +llvm::Value* Syscall2Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + arg1->codegen(generator), arg2->codegen(generator)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80), + arg1->codegen(generator), arg2->codegen(generator)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} + +llvm::Value* Syscall3Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rcx}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} + +llvm::Value* Syscall4Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rdx},{rcx}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx},{esi}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} + +llvm::Value* Syscall5Node::codegen(IRBuilder* generator) +{ + switch (Arguments::TargetTriple.getArch()) + { + case llvm::Triple::x86_64: { + auto i64Type = + llvm::FunctionType::get(llvm::IntegerType::getInt64Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i64Type, "syscall", "=r,{rax},{rdi},{rsi},{rdx},{rcx},{r8}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator), + arg5->codegen(generator)}); + break; + } + case llvm::Triple::x86: { + auto i32Type = + llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), false); + auto inlineAsm = llvm::InlineAsm::get(i32Type, "int $2", "=r,{eax},i,{ebx},{ecx},{edx},{esi},{edi}", true); + return generator->getBuilder()->CreateCall( + inlineAsm, + {llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), sys_num), + llvm::ConstantInt::get(llvm::IntegerType::getInt32Ty(generator->getBuilder()->getContext()), 0x80), + arg1->codegen(generator), arg2->codegen(generator), arg3->codegen(generator), arg4->codegen(generator), + arg5->codegen(generator)}); + break; + } + default: + Error::throw_error_without_location( + std::string("Unsupported arch for syscalls: ") + + Arguments::TargetTriple.getArchName(Arguments::TargetTriple.getArch()).str()); + break; + } +} diff --git a/src/AST/SyscallNode.h b/src/AST/SyscallNode.h new file mode 100644 index 0000000..19c9ade --- /dev/null +++ b/src/AST/SyscallNode.h @@ -0,0 +1,86 @@ +#pragma once +#include "ExprNode.h" + +class Syscall0Node final : public ExprNode +{ + int sys_num; + + public: + Syscall0Node(int syscall_number); + ~Syscall0Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +}; + +class Syscall1Node final : public ExprNode +{ + int sys_num; + std::shared_ptr arg1; + + public: + Syscall1Node(int syscall_number, std::shared_ptr arg1); + ~Syscall1Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +}; + +class Syscall2Node final : public ExprNode +{ + int sys_num; + std::shared_ptr arg1; + std::shared_ptr arg2; + + public: + Syscall2Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2); + ~Syscall2Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +}; + +class Syscall3Node final : public ExprNode +{ + int sys_num; + std::shared_ptr arg1; + std::shared_ptr arg2; + std::shared_ptr arg3; + + public: + Syscall3Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3); + ~Syscall3Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +}; + +class Syscall4Node final : public ExprNode +{ + int sys_num; + std::shared_ptr arg1; + std::shared_ptr arg2; + std::shared_ptr arg3; + std::shared_ptr arg4; + + public: + Syscall4Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3, std::shared_ptr arg4); + ~Syscall4Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +}; + +class Syscall5Node final : public ExprNode +{ + int sys_num; + std::shared_ptr arg1; + std::shared_ptr arg2; + std::shared_ptr arg3; + std::shared_ptr arg4; + std::shared_ptr arg5; + + public: + Syscall5Node(int syscall_number, std::shared_ptr arg1, std::shared_ptr arg2, + std::shared_ptr arg3, std::shared_ptr arg4, std::shared_ptr arg5); + ~Syscall5Node(); + + llvm::Value* codegen(IRBuilder* generator) override; +};