summaryrefslogtreecommitdiff
path: root/euler
diff options
context:
space:
mode:
authorBenji Dial <benji@benjidial.net>2024-07-27 16:57:39 -0400
committerBenji Dial <benji@benjidial.net>2024-07-27 16:57:39 -0400
commitfbfc078e9f44c1c1e95c9c484f1d5650bcf631b7 (patch)
treecab539c8cbbac81d895b6f8be695f3f53bf8f4d5 /euler
parent9af5588c30c4126a2800aae1afcb0de2c373dc6c (diff)
downloadhilbert-os-fbfc078e9f44c1c1e95c9c484f1d5650bcf631b7.tar.gz
lots and lots of userspace stuff
Diffstat (limited to 'euler')
-rw-r--r--euler/include/algorithm12
-rw-r--r--euler/include/cctype3
-rw-r--r--euler/include/cstdio22
-rw-r--r--euler/include/cstring11
-rw-r--r--euler/include/euler/heap.hpp10
-rw-r--r--euler/include/euler/start_process.hpp30
-rw-r--r--euler/include/euler/stream.hpp47
-rw-r--r--euler/include/euler/syscall.hpp234
-rw-r--r--euler/include/std/allocator.hpp30
-rw-r--r--euler/include/std/string.hpp80
-rw-r--r--euler/include/std/vector.hpp191
-rw-r--r--euler/include/string13
-rw-r--r--euler/include/type_traits23
-rw-r--r--euler/include/utility12
-rw-r--r--euler/include/vector61
-rw-r--r--euler/makefile14
-rw-r--r--euler/source/entry.cpp28
-rw-r--r--euler/source/euler/entry.cpp11
-rw-r--r--euler/source/euler/gcc.asm53
-rw-r--r--euler/source/euler/heap.cpp66
-rw-r--r--euler/source/euler/start_process.cpp35
-rw-r--r--euler/source/euler/stream.cpp151
-rw-r--r--euler/source/euler/syscall.asm144
-rw-r--r--euler/source/heap.cpp155
-rw-r--r--euler/source/io/fclose.cpp10
-rw-r--r--euler/source/io/fopen.cpp54
-rw-r--r--euler/source/io/fread.cpp9
-rw-r--r--euler/source/io/fseek.cpp11
-rw-r--r--euler/source/memory/delete.cpp17
-rw-r--r--euler/source/memory/new.cpp13
-rw-r--r--euler/source/std/cctype.cpp7
-rw-r--r--euler/source/std/cstdio.cpp59
-rw-r--r--euler/source/std/cstdlib.cpp19
-rw-r--r--euler/source/std/cstring.cpp36
-rw-r--r--euler/source/std/string.cpp86
-rw-r--r--euler/source/stream.cpp106
-rw-r--r--euler/source/strings/memcpy.cpp14
-rw-r--r--euler/source/strings/strlen.cpp12
-rw-r--r--euler/source/syscall.asm32
-rw-r--r--euler/source/syscall.cpp397
40 files changed, 1427 insertions, 891 deletions
diff --git a/euler/include/algorithm b/euler/include/algorithm
deleted file mode 100644
index 08702f9..0000000
--- a/euler/include/algorithm
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-namespace std {
-
- template <class t>
- void swap(t &a, t &b) {
- t tmp = a;
- a = b;
- b = tmp;
- }
-
-}
diff --git a/euler/include/cctype b/euler/include/cctype
new file mode 100644
index 0000000..2afc53d
--- /dev/null
+++ b/euler/include/cctype
@@ -0,0 +1,3 @@
+#pragma once
+
+extern "C" int isspace(int ch);
diff --git a/euler/include/cstdio b/euler/include/cstdio
index 75472c1..0dc42d0 100644
--- a/euler/include/cstdio
+++ b/euler/include/cstdio
@@ -1,20 +1,16 @@
#pragma once
#include <euler/stream.hpp>
-#include <stddef.h>
+#include <cstddef>
-namespace std {
+typedef euler::stream FILE;
- typedef euler::stream FILE;
+extern "C" FILE *fopen(const char *filename, const char *mode);
+extern "C" void fclose(FILE *stream);
- FILE *fopen(const char *filename, const char *mode);
- int fclose(FILE *stream);
+#define SEEK_CUR 2
+#define SEEK_END 1
+#define SEEK_SET 0
- int fseek(FILE *stream, long offset, int origin);
- #define SEEK_SET 0
- #define SEEK_CUR 2
- #define SEEK_END 1
-
- size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
-
-}
+extern "C" int fseek(FILE *stream, long offset, int origin);
+extern "C" size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
diff --git a/euler/include/cstring b/euler/include/cstring
index 45bc94e..cba5eb2 100644
--- a/euler/include/cstring
+++ b/euler/include/cstring
@@ -1,8 +1,9 @@
#pragma once
-#include <stddef.h>
+#include <cstddef>
-namespace std {
- size_t strlen(const char *str);
- void *memcpy(void *dest, const void *src, size_t count);
-}
+extern "C" void *memset(void *dest, int ch, size_t count);
+extern "C" void *memcpy(void *dest, const void *src, size_t count);
+
+extern "C" int strcmp(const char *lhs, const char *rhs);
+extern "C" size_t strlen(const char *str);
diff --git a/euler/include/euler/heap.hpp b/euler/include/euler/heap.hpp
index e2a4852..ce94eef 100644
--- a/euler/include/euler/heap.hpp
+++ b/euler/include/euler/heap.hpp
@@ -1,8 +1,10 @@
#pragma once
-#include <stdint.h>
+#include <cstddef>
+
+namespace euler::heap {
+
+ void *get_block(size_t length);
+ void return_block(void *start, size_t length);
-namespace euler {
- void *alloc(uint64_t bytes);
- void dealloc(void *start, uint64_t bytes);
}
diff --git a/euler/include/euler/start_process.hpp b/euler/include/euler/start_process.hpp
deleted file mode 100644
index 00ebbab..0000000
--- a/euler/include/euler/start_process.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-#include <euler/syscall.hpp>
-#include <vector>
-
-namespace euler {
-
- struct start_process {
-
- private:
- const char *path;
- uint64_t path_len;
- std::vector<__euler_env_var_spec> env_var_specs;
- std::vector<__euler_gift_stream_spec> gift_stream_specs;
-
- public:
- //path needs to stay valid through any call to start
- start_process(const char *path);
-
- //name and value need to stay valid through any call to start
- void add_env_variable(const char *name, const char *value);
-
- void gift_stream(
- __euler_stream_handle to_gifter, __euler_stream_handle to_giftee);
-
- __euler_stream_result start(__euler_process_handle &handle_out);
-
- };
-
-}
diff --git a/euler/include/euler/stream.hpp b/euler/include/euler/stream.hpp
index a364ec4..741d863 100644
--- a/euler/include/euler/stream.hpp
+++ b/euler/include/euler/stream.hpp
@@ -7,41 +7,42 @@ namespace euler {
class stream {
public:
- virtual ~stream();
- virtual bool try_read(void *into, uint64_t bytes) = 0;
- virtual bool try_seek(__euler_seek_from from, int64_t offset) = 0;
+ virtual ~stream() {}
- };
+ virtual syscall::stream_result seek(
+ euler::syscall::seek_from from, int64_t offset) = 0;
- class file_stream : public stream {
+ virtual std::pair<uint64_t, syscall::stream_result>
+ read(uint64_t bytes, void *into) = 0;
- private:
+ virtual void close() = 0;
- __euler_stream_handle handle;
- bool is_readable;
- bool is_writable;
- uint64_t length;
- uint64_t offset;
+ };
- uint8_t *buffer;
- uint64_t buffer_offset;
- uint64_t buffer_size;
- bool buffer_dirty;
+ class file_stream : public stream {
- void write_buffer();
+ syscall::stream_handle handle;
+ bool may_read;
- public:
+ bool buffer_loaded;
+ uint64_t buffer_start;
+ uint8_t buffer[1024];
- bool good;
+ uint64_t length;
+ uint64_t position;
+ public:
file_stream(
- __euler_stream_handle handle, bool is_readable, bool is_writable,
- bool clear, bool seek_to_end);
+ syscall::stream_handle handle, bool may_read,
+ uint64_t length, uint64_t position);
+
+ virtual syscall::stream_result seek(
+ syscall::seek_from from, int64_t offset) override;
- ~file_stream();
+ virtual std::pair<uint64_t, syscall::stream_result>
+ read(uint64_t bytes, void *into) override;
- bool try_read(void *into, uint64_t bytes) override;
- bool try_seek(__euler_seek_from from, int64_t offset) override;
+ virtual void close() override;
};
diff --git a/euler/include/euler/syscall.hpp b/euler/include/euler/syscall.hpp
index 981925f..64456ae 100644
--- a/euler/include/euler/syscall.hpp
+++ b/euler/include/euler/syscall.hpp
@@ -1,102 +1,136 @@
#pragma once
-#include <stdint.h>
-
-enum __euler_stream_result : uint64_t {
- __EULER_SR_SUCCESS = 0,
- __EULER_SR_BAD_HANDLE,
- __EULER_SR_IO_ERROR,
- __EULER_SR_OUT_OF_BOUNDS,
- __EULER_SR_DOES_NOT_EXIST,
- __EULER_SR_NOT_A_REGULAR_FILE,
- __EULER_SR_NOT_AN_EXECUTABLE,
- __EULER_SR_NOT_WRITABLE,
- __EULER_SR_NOT_SEEKABLE,
- __EULER_SR_SOCKET_ID_ALREADY_IN_USE,
- __EULER_SR_SOCKET_ID_NOT_IN_USE,
- __EULER_SR_SOCKET_LISTENER_CLOSED,
- __EULER_SR_OTHER_END_CLOSED,
- __EULER_SR_ALREADY_EXISTS,
- __EULER_SR_NOT_SIZED
-};
-
-enum __euler_seek_from : uint8_t {
- __EULER_SF_BEGINNING = 0,
- __EULER_SF_END,
- __EULER_SF_CURRENT_POSITION
-};
-
-typedef uint64_t __euler_stream_handle;
-typedef uint64_t __euler_process_handle;
-
-extern "C" __euler_stream_result __euler_open_file(
- const char *path, uint64_t path_len, __euler_stream_handle &handle_out,
- bool allow_creation, bool only_allow_creation);
-
-extern "C" [[noreturn]] void __euler_end_this_thread(int32_t exit_code);
-
-extern "C" __euler_stream_result __euler_seek_stream(
- __euler_stream_handle handle, __euler_seek_from from, int64_t offset);
-
-extern "C" __euler_stream_result __euler_set_stream_length(
- __euler_stream_handle handle, uint64_t new_length);
-
-extern "C" void __euler_close_stream(__euler_stream_handle handle);
-
-extern "C" __euler_stream_result __euler_get_stream_length(
- __euler_stream_handle handle, uint64_t &length_out);
-
-extern "C" void *__euler_get_new_pages(uint64_t count);
-
-extern "C" __euler_stream_result __euler_write_to_stream(
- __euler_stream_handle handle, uint64_t count, const void *buffer);
-
-extern "C" __euler_stream_result __euler_read_from_stream(
- __euler_stream_handle handle, uint64_t count, void *buffer);
-
-extern "C" uint32_t *__euler_get_framebuffer(
- uint32_t &width_out, uint32_t &height_out, uint32_t &pitch_out);
-
-extern "C" uint32_t __euler_encode_color(uint8_t r, uint8_t g, uint8_t b);
-
-enum __euler_mouse_buttons : uint8_t {
- __EULER_MB_LEFT = 1,
- __EULER_MB_RIGHT = 2,
- __EULER_MB_MIDDLE = 4
-};
-
-enum __euler_input_packet_type : uint8_t {
- __EULER_IPT_MOUSE = 1,
- __EULER_IPT_KEYBOARD = 2
-};
-
-extern "C" __euler_input_packet_type __euler_get_input_packet(
- __euler_mouse_buttons &buttons_out, int16_t &x_change_out,
- int16_t &y_change_out, uint32_t &keyboard_packet_out);
-
-struct [[gnu::packed]] __euler_env_var_spec {
- uint64_t name_len;
- const char *name;
- uint64_t value_len;
- const char *value;
-};
-
-struct [[gnu::packed]] __euler_gift_stream_spec {
- __euler_stream_handle stream_handle_to_gifter;
- __euler_stream_handle stream_handle_to_giftee;
-};
-
-struct [[gnu::packed]] __euler_process_start_info {
- uint64_t file_path_length;
- const char *file_path;
- uint64_t env_var_count;
- const __euler_env_var_spec *env_vars;
- uint64_t gift_stream_count;
- const __euler_gift_stream_spec *gift_streams;
-};
-
-extern "C" __euler_stream_result __euler_start_process(
- const __euler_process_start_info &info, __euler_process_handle &handle_out);
-
-extern "C" __euler_stream_result __euler_get_other_end_process_handle(
- __euler_stream_handle handle_in, __euler_process_handle &handle_out);
+#include <optional>
+#include <cstdint>
+#include <utility>
+#include <variant>
+#include <string>
+#include <vector>
+
+namespace euler::syscall {
+
+ enum class stream_result : uint64_t {
+ success,
+ bad_handle,
+ io_error,
+ out_of_bounds,
+ does_not_exist,
+ not_a_regular_file,
+ not_an_executable,
+ not_writable,
+ not_seekable,
+ socket_id_already_used,
+ socket_id_not_in_use,
+ socket_listener_closed,
+ other_end_closed,
+ already_exists,
+ not_sized,
+ not_readable
+ };
+
+ enum class seek_from : uint8_t {
+ beginning,
+ end,
+ current_position
+ };
+
+ struct mouse_packet {
+ bool left_button_down;
+ bool right_button_down;
+ bool middle_button_down;
+ int16_t x_changed;
+ int16_t y_changed;
+ };
+
+ struct key_packet {
+ bool was_key_up_event;
+ bool num_lock;
+ bool caps_lock;
+ bool right_win;
+ bool left_win;
+ bool right_alt;
+ bool left_alt;
+ bool right_ctrl;
+ bool left_ctrl;
+ bool right_shift;
+ bool left_shift;
+ uint8_t key_code;
+ };
+
+ typedef uint32_t encoded_color;
+ typedef uint64_t stream_handle;
+ typedef uint64_t listener_handle;
+ typedef uint64_t process_handle;
+
+ encoded_color encode_color(
+ uint8_t r, uint8_t g, uint8_t b);
+
+ void get_framebuffer(
+ encoded_color *&buffer_out, uint32_t &width_out,
+ uint32_t &height_out, uint32_t &pitch_out);
+
+ stream_result open_file(
+ const std::string &file_path, bool allow_creation,
+ bool only_allow_creation, stream_handle &handle_out);
+
+ [[noreturn]] void end_this_thread(int32_t exit_code);
+
+ void *get_new_pages(uint64_t n_pages);
+
+ std::variant<mouse_packet, key_packet> get_input_packet();
+
+ void create_private_socket(
+ stream_handle &end_1_out, stream_handle &end_2_out);
+
+ stream_result create_socket_listener(
+ const std::string &id, listener_handle &handle_out);
+
+ void stop_socket_listener(listener_handle handle);
+
+ stream_result accept_socket_connection(
+ listener_handle listener, stream_handle &stream_out);
+
+ stream_result connect_to_socket(
+ const std::string &id, stream_handle &handle_out);
+
+ void close_stream(stream_handle handle);
+
+ stream_result seek_stream(
+ stream_handle handle, seek_from from, int64_t offset);
+
+ stream_result read_from_stream(
+ stream_handle handle, uint64_t bytes, void *into);
+
+ stream_result write_to_stream(
+ stream_handle handle, uint64_t bytes, const void *from);
+
+ stream_result get_stream_length(
+ stream_handle handle, uint64_t &length_out);
+
+ stream_result start_process(
+ const std::string &file_path,
+ const std::vector<std::pair<std::string, std::string>> &environment_variables,
+ const std::vector<std::pair<stream_handle, stream_result>> &gifted_streams,
+ process_handle &handle_out);
+
+ [[noreturn]] void end_this_process(int32_t exit_code);
+
+ stream_result set_stream_length(
+ stream_handle handle, uint64_t new_length);
+
+ stream_result get_other_end_process_handle(
+ stream_handle stream, process_handle &process_out);
+
+ //entry_point must not return
+ void start_thread(void (*entry_point)(uint64_t), uint64_t arg);
+
+ //entry_point must not return
+ void start_thread(void (*entry_point)());
+
+ //return value is number of bytes cleared
+ uint64_t clear_socket_read_queue(stream_handle handle);
+
+ std::optional<std::string> try_get_environment_variable(
+ const std::string &name);
+
+}
diff --git a/euler/include/std/allocator.hpp b/euler/include/std/allocator.hpp
new file mode 100644
index 0000000..32ba005
--- /dev/null
+++ b/euler/include/std/allocator.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <euler/heap.hpp>
+
+namespace std {
+
+ template <class T>
+ struct allocator {
+
+ using value_type = T;
+
+ constexpr allocator() noexcept {}
+ constexpr allocator(const allocator &other) noexcept {}
+
+ template <class U>
+ constexpr allocator(const allocator<U> &other) noexcept {}
+
+ constexpr ~allocator() {}
+
+ constexpr T *allocate(size_t n) {
+ return (T *)euler::heap::get_block(n * sizeof(T));
+ }
+
+ constexpr void deallocate(T *p, size_t n) {
+ euler::heap::return_block(p, n * sizeof(T));
+ }
+
+ };
+
+}
diff --git a/euler/include/std/string.hpp b/euler/include/std/string.hpp
new file mode 100644
index 0000000..7ccdbc2
--- /dev/null
+++ b/euler/include/std/string.hpp
@@ -0,0 +1,80 @@
+#pragma once
+
+#include <cstddef>
+#include <vector>
+
+namespace std {
+
+ class string {
+
+ std::vector<char> characters;
+
+ public:
+ constexpr string() : characters({'\0'}) {}
+
+ constexpr string(const string &other)
+ : characters(other.characters) {}
+
+ constexpr string(string &&other) noexcept
+ : characters(std::move(other.characters)) {
+ other.characters.push_back('\0');
+ }
+
+ constexpr string(const char *s) {
+ size_t count = 0;
+ while (s[count] != '\0')
+ ++count;
+ characters.resize(count + 1);
+ for (size_t i = 0; i <= count; ++i)
+ characters[i] = s[i];
+ }
+
+ constexpr ~string() {}
+
+ constexpr string &operator =(const string &str) {
+ characters = str.characters;
+ return *this;
+ }
+
+ constexpr string &operator =(string &&str) noexcept {
+ characters = std::move(str.characters);
+ str.characters.push_back('\0');
+ return *this;
+ }
+
+ constexpr size_t size() const noexcept {
+ return characters.size() - 1;
+ }
+
+ constexpr void resize(size_t count) {
+ if (count < characters.size() - 1) {
+ characters.resize(count + 1);
+ characters[count] = '\0';
+ }
+ else if (count > characters.size() - 1)
+ characters.resize(count + 1);
+ }
+
+ constexpr void clear() noexcept {
+ resize(0);
+ }
+
+ constexpr const char *data() const noexcept {
+ return characters.data();
+ }
+
+ constexpr char *data() noexcept {
+ return characters.data();
+ }
+
+ constexpr char &operator[](size_t pos) {
+ return characters[pos];
+ }
+
+ constexpr const char &operator[](size_t pos) const {
+ return characters[pos];
+ }
+
+ };
+
+}
diff --git a/euler/include/std/vector.hpp b/euler/include/std/vector.hpp
new file mode 100644
index 0000000..a1ac21d
--- /dev/null
+++ b/euler/include/std/vector.hpp
@@ -0,0 +1,191 @@
+#pragma once
+
+#include <memory>
+
+namespace std {
+
+ template <class T, class Allocator = std::allocator<T>>
+ class vector {
+
+ public:
+ using size_type = size_t;
+ using value_type = T;
+ using reference = value_type &;
+ using const_reference = const value_type &;
+
+ private:
+ Allocator _alloc;
+ size_type _capacity;
+ size_type _size;
+ T *_data;
+
+ constexpr void expand_capacity_to(size_type at_least) {
+
+ size_type new_capacity = _capacity == 0 ? 1 : _capacity;
+ while (new_capacity < at_least)
+ new_capacity *= 2;
+ if (new_capacity == _capacity)
+ return;
+
+ T *new_data = _alloc.allocate(new_capacity);
+ for (size_type i = 0; i < _size; ++i) {
+ std::construct_at(new_data + i, std::move(_data[i]));
+ std::destroy_at(_data + i);
+ }
+ if (_capacity > 0)
+ _alloc.deallocate(_data, _capacity);
+
+ _capacity = new_capacity;
+ _data = new_data;
+
+ }
+
+ public:
+ constexpr vector() noexcept(noexcept(Allocator()))
+ : _alloc(), _capacity(0), _size(0), _data(0) {}
+
+ constexpr vector(const vector &other)
+ : _alloc(), _capacity(other._size), _size(other._size),
+ _data(_alloc.allocate(_capacity)) {
+ for (size_type i = 0; i < _size; ++i)
+ std::construct_at(_data + i, other._data[i]);
+ }
+
+ constexpr vector(vector &&other) noexcept
+ : _alloc(std::move(other._alloc)), _capacity(other._capacity),
+ _size(other._size), _data(other._data) {
+ other._capacity = 0;
+ other._size = 0;
+ }
+
+ constexpr vector(
+ std::initializer_list<T> init, const Allocator &alloc = Allocator())
+ : _alloc(alloc), _capacity(init.size()),
+ _size(init.size()), _data(_alloc.allocate(_capacity)) {
+ for (size_type i = 0; i < _size; ++i)
+ std::construct_at(_data + i, init.begin()[i]);
+ }
+
+ explicit vector(size_type count)
+ : _alloc(), _capacity(count), _size(count),
+ _data(_alloc.allocate(_capacity)) {
+ for (size_type i = 0; i < _size; ++i)
+ std::construct_at(_data + i);
+ }
+
+ constexpr ~vector() {
+ if (_capacity > 0) {
+ for (size_type i = 0; i < _size; ++i)
+ std::destroy_at(_data + i);
+ _alloc.deallocate(_data, _capacity);
+ }
+ }
+
+ constexpr vector &operator =(const vector &other) {
+
+ if (&other == this)
+ return *this;
+
+ expand_capacity_to(other._size);
+
+ for (size_type i = 0; i < _size; ++i)
+ std::destroy_at(_data + i);
+
+ for (size_type i = 0; i < other._size; ++i) {
+ std::construct_at(_data + i, std::move(other._data[i]));
+ std::destroy_at(other._data + i);
+ }
+
+ _size = other._size;
+ return *this;
+
+ }
+
+ constexpr vector &operator =(vector &&other)
+ noexcept(
+ std::allocator_traits<Allocator>::
+ propagate_on_container_move_assignment::value ||
+ std::allocator_traits<Allocator>::
+ is_always_equal::value) {
+
+ if (&other == this)
+ return *this;
+
+ if (_capacity > 0) {
+ for (size_type i = 0; i < _size; ++i)
+ std::destroy_at(_data + i);
+ _alloc.deallocate(_data, _capacity);
+ }
+
+ _alloc = std::move(other._alloc);
+ _capacity = other._capacity;
+ _size = other._size;
+ _data = other._data;
+
+ other._capacity = 0;
+ other._size = 0;
+
+ return *this;
+
+ }
+
+ constexpr size_type size() const noexcept {
+ return _size;
+ }
+
+ constexpr T *data() noexcept {
+ return _data;
+ }
+
+ constexpr const T *data() const noexcept {
+ return _data;
+ }
+
+ constexpr reference operator[](size_type pos) {
+ return _data[pos];
+ }
+
+ constexpr const_reference operator[](size_type pos) const {
+ return _data[pos];
+ }
+
+ constexpr reference back() {
+ return _data[_size - 1];
+ }
+
+ constexpr const_reference back() const {
+ return _data[_size - 1];
+ }
+
+ constexpr void resize(size_type count) {
+
+ if (count < _size) {
+ for (size_type i = count; i < _size; ++i)
+ std::destroy_at(_data + i);
+ _size = count;
+ }
+
+ else if (count > _size) {
+ expand_capacity_to(count);
+ for (size_type i = _size; i < count; ++i)
+ std::construct_at(_data + i);
+ _size = count;
+ }
+
+ }
+
+ constexpr void push_back(const T &value) {
+ expand_capacity_to(_size + 1);
+ std::construct_at(_data + _size, value);
+ ++_size;
+ }
+
+ constexpr void push_back(T &&value) {
+ expand_capacity_to(_size + 1);
+ std::construct_at(_data + _size, std::move(value));
+ ++_size;
+ }
+
+ };
+
+}
diff --git a/euler/include/string b/euler/include/string
new file mode 100644
index 0000000..ce42b9e
--- /dev/null
+++ b/euler/include/string
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <std/string.hpp>
+
+namespace std {
+
+ int stoi(const std::string &str, size_t *pos = 0, int base = 10);
+
+ std::string to_string(int value);
+
+ std::string operator +(std::string &&lhs, std::string &&rhs);
+
+}
diff --git a/euler/include/type_traits b/euler/include/type_traits
deleted file mode 100644
index fcea013..0000000
--- a/euler/include/type_traits
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-namespace std {
-
- template <class t>
- struct remove_reference {
- typedef t type;
- };
-
- template <class t>
- struct remove_reference<t &> {
- typedef t type;
- };
-
- template <class t>
- struct remove_reference<t &&> {
- typedef t type;
- };
-
- template <class t>
- using remove_reference_t = typename remove_reference<t>::type;
-
-}
diff --git a/euler/include/utility b/euler/include/utility
deleted file mode 100644
index 23648c4..0000000
--- a/euler/include/utility
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include <type_traits>
-
-namespace std {
-
- template <class t>
- constexpr std::remove_reference_t<t> &&move(t &&x) {
- return static_cast<std::remove_reference_t<t> &&>(x);
- }
-
-}
diff --git a/euler/include/vector b/euler/include/vector
index f5083ed..2184475 100644
--- a/euler/include/vector
+++ b/euler/include/vector
@@ -1,62 +1,3 @@
#pragma once
-#include <stddef.h>
-#include <utility>
-
-namespace std {
-
- template <class t>
- class vector {
-
- t *buffer;
- size_t buffer_length;//always positive
- size_t count;
-
- public:
- vector() : buffer(new t[16]), buffer_length(16), count(0) {}
-
- ~vector() {
- delete[] buffer;
- }
-
- t &operator[](size_t pos) {
- return buffer[pos];
- }
-
- const t &operator[](size_t pos) const {
- return buffer[pos];
- }
-
- t *data() {
- return buffer;
- }
-
- const t *data() const {
- return buffer;
- }
-
- size_t size() const {
- return count;
- }
-
- void reserve(size_t new_length) {
- if (new_length <= buffer_length)
- return;
- t *new_buffer = new t[new_length];
- for (size_t i = 0; i < count; ++i)
- new_buffer[i] = std::move(buffer[i]);
- delete[] buffer;
- buffer = new_buffer;
- buffer_length = new_length;
- }
-
- void push_back(t &&value) {
- if (count == buffer_length)
- reserve(count * 2);
- buffer[count++] = std::move(value);
- }
-
- //TODO
- };
-
-}
+#include <std/vector.hpp>
diff --git a/euler/makefile b/euler/makefile
index 1767d75..62716f6 100644
--- a/euler/makefile
+++ b/euler/makefile
@@ -1,7 +1,6 @@
-LIBSTDCPP_SOURCES = euler/stream.cpp strings/strlen.cpp euler/syscall.asm \
- euler/entry.cpp io/fopen.cpp euler/gcc.asm memory/delete.cpp euler/heap.cpp \
- memory/new.cpp io/fclose.cpp io/fread.cpp strings/memcpy.cpp io/fseek.cpp \
- euler/start_process.cpp
+LIBC_SOURCES = \
+ entry.cpp std/string.cpp std/cstring.cpp syscall.cpp std/cstdlib.cpp \
+ heap.cpp syscall.asm std/cctype.cpp std/cstdio.cpp stream.cpp
clean:
rm -rf build
@@ -12,12 +11,12 @@ build/%.asm.o: source/%.asm
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)
- $(HILBERT_CC) -c $^ -o $@
+ $(HILBERT_CC) -ffreestanding -c $^ -o $@
build/crt0.o: build/empty.asm.o
cp $^ $@
-build/libc.a: build/empty.asm.o
+build/libc.a: ${LIBC_SOURCES:%=build/%.o}
$(HILBERT_AR) rcs $@ $^
build/libg.a: build/empty.asm.o
@@ -25,6 +24,3 @@ build/libg.a: build/empty.asm.o
build/libm.a: build/empty.asm.o
$(HILBERT_AR) rcs $@ $^
-
-build/libstdc++.a: ${LIBSTDCPP_SOURCES:%=build/%.o}
- $(HILBERT_AR) rcs $@ $^
diff --git a/euler/source/entry.cpp b/euler/source/entry.cpp
new file mode 100644
index 0000000..e79209c
--- /dev/null
+++ b/euler/source/entry.cpp
@@ -0,0 +1,28 @@
+#include <euler/syscall.hpp>
+#include <cstdlib>
+#include <string>
+
+int main(int argc, char **argv);
+
+extern "C" [[noreturn]] void _start() {
+
+ auto argc_raw = euler::syscall::try_get_environment_variable("ARGC");
+ int argc = argc_raw.has_value() ? std::stoi(argc_raw.value()) : 0;
+
+ std::vector<std::string> argv;
+
+ for (int i = 0; i < argc; ++i) {
+ std::string arg_name = std::string("ARGV") + std::to_string(i);
+ auto arg_raw = euler::syscall::try_get_environment_variable(arg_name);
+ argv.push_back(arg_raw.has_value() ? arg_raw.value() : "");
+ }
+
+ std::vector<char *> c_argv(argc);
+ for (int i = 0; i < argc; ++i)
+ c_argv[i] = argv[i].data();
+
+ int exit_code = main(argc, c_argv.data());
+
+ euler::syscall::end_this_process(exit_code);
+
+}
diff --git a/euler/source/euler/entry.cpp b/euler/source/euler/entry.cpp
deleted file mode 100644
index 69611b7..0000000
--- a/euler/source/euler/entry.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <euler/syscall.hpp>
-
-int main(int argc, char **argv);
-
-extern "C" [[noreturn]] void _start() {
- //TODO: call global constructors
- //TODO: get argc, argv from environment
- int exit_code = main(0, 0);
- //TODO: call global destructors
- __euler_end_this_thread(exit_code);
-}
diff --git a/euler/source/euler/gcc.asm b/euler/source/euler/gcc.asm
deleted file mode 100644
index 6fc6fd5..0000000
--- a/euler/source/euler/gcc.asm
+++ /dev/null
@@ -1,53 +0,0 @@
-bits 64
-
-global strlen
-
-section .text
-
-strlen:
- xor rax, rax
-.loop:
- mov rdx, qword [rdi]
- test edx, 0xff
- jz .plus0
- test edx, 0xff00
- jz .plus1
- test edx, 0xff0000
- jz .plus2
- test edx, 0xff000000
- jz .plus3
- shr rdx, 32
- test edx, 0xff
- jz .plus4
- test edx, 0xff00
- jz .plus5
- test edx, 0xff0000
- jz .plus6
- test edx, 0xff000000
- jz .plus7
- add rax, 8
- add rdi, 8
- jmp .loop
-.plus0:
- ret
-.plus1:
- add rax, 1
- ret
-.plus2:
- add rax, 2
- ret
-.plus3:
- add rax, 3
- ret
-.plus4:
- add rax, 4
- ret
-.plus5:
- add rax, 5
- ret
-.plus6:
- add rax, 6
- ret
-.plus7:
- add rax, 7
- ret
diff --git a/euler/source/euler/heap.cpp b/euler/source/euler/heap.cpp
deleted file mode 100644
index f7d407f..0000000
--- a/euler/source/euler/heap.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <euler/syscall.hpp>
-#include <euler/heap.hpp>
-
-namespace euler {
-
- static uint64_t *last_chunk_info_page = 0;
-
- void add_record(uint64_t start, uint64_t length) {
- uint64_t dual_start = start ^ length;
- for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
- for (int i = 0; i < 255; ++i)
- if (cip[i * 2] == length && cip[i * 2 + 1] == dual_start) {
- cip[i * 2] = length * 2;
- cip[i * 2 + 1] &= start;
- return;
- }
- for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
- for (int i = 0; i < 255; ++i)
- if (cip[i * 2] == 0) {
- cip[i * 2] = length;
- cip[i * 2 + 1] = start;
- return;
- }
- uint64_t *new_cip = (uint64_t *)__euler_get_new_pages(1);
- new_cip[0] = length;
- new_cip[1] = start;
- for (int i = 1; i < 255; ++i)
- new_cip[i * 2] = 0;
- new_cip[510] = (uint64_t)last_chunk_info_page;
- last_chunk_info_page = new_cip;
- }
-
- void *alloc(uint64_t bytes) {
- for (uint64_t *cip = last_chunk_info_page; cip; cip = (uint64_t *)cip[510])
- for (int i = 0; i < 255; ++i)
- if (cip[i * 2] >= bytes) {
- uint64_t start = cip[i * 2 + 1];
- uint64_t extra_length = cip[i * 2] - bytes;
- cip[i * 2] = 0;
- if (extra_length > 0)
- dealloc((void *)(start + bytes), extra_length);
- return (void *)start;
- }
- uint64_t pages_needed = (bytes - 1) / 4096 + 1;
- uint64_t start = (uint64_t)__euler_get_new_pages(pages_needed);
- if (bytes != pages_needed * 4096)
- dealloc((void *)(start + bytes), pages_needed * 4096 - bytes);
- return (void *)start;
- }
-
- //this implementation is a little lazy
- void dealloc(void *start, uint64_t bytes) {
- uint64_t s = (uint64_t)start;
- while (bytes > 0) {
- uint64_t l = 1;
- do
- l *= 2;
- while (l <= bytes && s % l == 0);
- l /= 2;
- add_record(s, l);
- s += l;
- bytes -= l;
- }
- }
-
-}
diff --git a/euler/source/euler/start_process.cpp b/euler/source/euler/start_process.cpp
deleted file mode 100644
index 64e16c5..0000000
--- a/euler/source/euler/start_process.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <euler/start_process.hpp>
-#include <cstring>
-
-namespace euler {
-
- start_process::start_process(const char *path)
- : path(path), path_len(std::strlen(path)) {}
-
- void start_process::add_env_variable(const char *name, const char *value) {
- env_var_specs.push_back({
- .name_len = std::strlen(name), .name = name,
- .value_len = std::strlen(value), .value = value });
- }
-
- void start_process::gift_stream(
- __euler_stream_handle to_gifter, __euler_stream_handle to_giftee) {
- gift_stream_specs.push_back({
- .stream_handle_to_gifter = to_gifter,
- .stream_handle_to_giftee = to_giftee });
- }
-
- __euler_stream_result start_process::start(
- __euler_process_handle &handle_out) {
- __euler_process_start_info info = {
- .file_path_length = path_len,
- .file_path = path,
- .env_var_count = env_var_specs.size(),
- .env_vars = env_var_specs.data(),
- .gift_stream_count = gift_stream_specs.size(),
- .gift_streams = gift_stream_specs.data(),
- };
- return __euler_start_process(info, handle_out);
- }
-
-}
diff --git a/euler/source/euler/stream.cpp b/euler/source/euler/stream.cpp
deleted file mode 100644
index 950f3c5..0000000
--- a/euler/source/euler/stream.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-#include <euler/stream.hpp>
-#include <cstring>
-
-namespace euler {
-
- stream::~stream() {}
-
- void file_stream::write_buffer() {
- if (__euler_write_to_stream(handle, buffer_size, buffer)
- != __EULER_SR_SUCCESS)
- good = false;//TODO: more precise error reporting
- else
- buffer_dirty = false;
- }
-
- file_stream::file_stream(
- __euler_stream_handle handle, bool is_readable, bool is_writable,
- bool clear, bool seek_to_end)
-
- : handle(handle), is_readable(is_readable), is_writable(is_writable),
- buffer(0), good(true) {
-
- if (clear) {
- if (__euler_set_stream_length(handle, 0) != __EULER_SR_SUCCESS) {
- good = false;
- return;
- }
- length = 0;
- }
-
- else if (__euler_get_stream_length(handle, length) != __EULER_SR_SUCCESS) {
- good = false;
- return;
- }
-
- if (seek_to_end) {
- if (__euler_seek_stream(handle, __EULER_SF_END, 0)
- != __EULER_SR_SUCCESS) {
- good = false;
- return;
- }
- offset = length;
- }
-
- else
- offset = 0;
-
- }
-
- file_stream::~file_stream() {
- if (buffer) {
- if (buffer_dirty)
- write_buffer();
- delete[] buffer;
- }
- __euler_close_stream(handle);
- }
-
- bool file_stream::try_read(void *into, uint64_t bytes) {
-
- if (bytes == 0)
- return true;
-
- if (offset + bytes > length)
- return false;
-
- if (buffer) {
- uint64_t start = offset > buffer_offset ? offset : buffer_offset;
- uint64_t end = offset + bytes < buffer_offset + buffer_size
- ? offset + bytes : buffer_offset + buffer_size;
- if (end > start) {
-
- uint64_t real_end = offset + bytes;
-
- std::memcpy(
- (uint8_t *)into + start - offset, buffer + start - buffer_offset,
- end - start);
- if (start != offset)
- if (!try_read(into, start - offset))
- return false;
-
- if (end != real_end) {
- if (!try_seek(__EULER_SF_BEGINNING, end))
- return false;
- if (!try_read((uint8_t *)into + end, real_end - end))
- return false;
- }
-
- else if (offset != real_end)
- if (!try_seek(__EULER_SF_BEGINNING, real_end))
- return false;
-
- return true;
-
- }
- }
-
- if (buffer_dirty) {
- write_buffer();
- if (!good)
- return false;
- }
-
- //1024 is arbitrary
- buffer_size = length - offset < 1024 ? length - offset : 1024;
-
- if (buffer != 0)
- delete[] buffer;
-
- buffer = new uint8_t[buffer_size];
- buffer_dirty = false;
- buffer_offset = offset;
-
- if (__euler_read_from_stream(handle, buffer_size, buffer)
- != __EULER_SR_SUCCESS) {
- delete[] buffer;
- buffer = 0;
- return false;
- }
-
- uint64_t read_this_buffer = buffer_size < bytes ? buffer_size : bytes;
- std::memcpy(into, buffer, read_this_buffer);
- offset += read_this_buffer;
-
- if (read_this_buffer == bytes)
- return true;
-
- return try_read(
- (uint8_t *)into + read_this_buffer, bytes - read_this_buffer);
-
- }
-
- bool file_stream::try_seek(__euler_seek_from from, int64_t offset) {
- if (__euler_seek_stream(handle, from, offset) != __EULER_SR_SUCCESS)
- return false;
- switch (from) {
- case __EULER_SF_BEGINNING:
- this->offset = offset;
- return true;
- case __EULER_SF_END:
- this->offset = length + offset;
- return true;
- case __EULER_SF_CURRENT_POSITION:
- this->offset += offset;
- return true;
- default:
- return false;
- }
- }
-
-}
diff --git a/euler/source/euler/syscall.asm b/euler/source/euler/syscall.asm
deleted file mode 100644
index 64f08f8..0000000
--- a/euler/source/euler/syscall.asm
+++ /dev/null
@@ -1,144 +0,0 @@
-bits 64
-
-global __euler_open_file
-global __euler_close_stream
-global __euler_get_new_pages
-global __euler_write_to_stream
-global __euler_seek_stream
-global __euler_get_stream_length
-global __euler_set_stream_length
-global __euler_end_this_thread
-global __euler_read_from_stream
-global __euler_get_framebuffer
-global __euler_encode_color
-global __euler_get_input_packet
-global __euler_start_process
-global __euler_get_other_end_process_handle
-
-section .text
-
-__euler_open_file:
- mov rax, 2
- push rdx
- xor rdx, rdx
- or rdx, r8
- shl r9, 1
- or rdx, r9
- syscall
- pop rdx
- mov qword [rdx], rdi
- ret
-
-__euler_close_stream:
- mov rax, 11
- syscall
- ret
-
-__euler_get_new_pages:
- mov rax, 4
- syscall
- ret
-
-__euler_write_to_stream:
- mov rax, 14
- syscall
- ret
-
-__euler_seek_stream:
- mov rax, 12
- syscall
- ret
-
-__euler_get_stream_length:
- push rsi
- mov rax, 15
- syscall
- pop rsi
- mov qword [rsi], rdi
- ret
-
-__euler_set_stream_length:
- mov rax, 18
- syscall
- ret
-
-__euler_end_this_thread:
- mov rax, 3
- syscall
-
-__euler_read_from_stream:
- mov rax, 13
- syscall
- ret
-
-__euler_get_framebuffer:
- push rdi
- push rsi
- push rdx
- mov rax, 1
- syscall
- pop rdx
- mov dword [rdx], esi
- pop rdx
- pop rsi
- mov dword [rsi], edi
- shr rdi, 32
- mov dword [rdx], edi
- ret
-
-__euler_encode_color:
- xor ah, ah
- mov al, dl
- shl ax, 8
- mov al, sil
- shl eax, 8
- mov al, dil
- mov edi, eax
- xor rax, rax
- syscall
- ret
-
-__euler_get_input_packet:
- push rdi
- push rsi
- push rdx
- push rcx
- mov rax, 5
- syscall
-
- test al, 0x80
- jnz .mouse_packet
-
- pop rcx
- mov dword [rcx], edi
- add rsp, 24
- mov al, 2
- ret
-
-.mouse_packet:
- add rsp, 8
- pop rdx
- mov word [rdx], si
- pop rdx
- mov word [rdx], di
- pop rdx
- and al, 0x7f
- mov byte [rdx], al
- mov al, 1
- ret
-
-__euler_start_process:
- push rsi
- mov rax, 16
- syscall
- pop rsi
- mov qword [rsi], rdi
- ret
-
-__euler_get_other_end_process_handle:
- push rsi
- mov rax, 19
- syscall
- pop rsi
- mov qword [rsi], rdi
- ret
diff --git a/euler/source/heap.cpp b/euler/source/heap.cpp
new file mode 100644
index 0000000..dc92e5d
--- /dev/null
+++ b/euler/source/heap.cpp
@@ -0,0 +1,155 @@
+#include <euler/syscall.hpp>
+#include <euler/heap.hpp>
+#include <cstdint>
+
+namespace euler::heap {
+
+ struct heap_aligned_entry {
+ size_t start_vaddr;
+ size_t length;
+ heap_aligned_entry *prev;
+ heap_aligned_entry *next;
+ };
+
+ struct unused_heap_entries_page {
+ heap_aligned_entry *unused[510];
+ unused_heap_entries_page *prev;
+ uint16_t unused_in_this_page;
+ };
+
+ heap_aligned_entry *first_entry = 0;
+ heap_aligned_entry *last_entry = 0;
+ unused_heap_entries_page *last_page = 0;
+
+ void mark_entry_unused(heap_aligned_entry *entry) {
+
+ for (unused_heap_entries_page *page = last_page; page != 0; page = page->prev) {
+ if (page->unused_in_this_page == 510)
+ continue;
+ for (uint16_t i = 0; i < 510; ++i)
+ if (page->unused[i] == 0) {
+ page->unused[i] = entry;
+ ++page->unused_in_this_page;
+ return;
+ }
+ }
+
+ unused_heap_entries_page *page = (unused_heap_entries_page *)euler::syscall::get_new_pages(1);
+ page->prev = last_page;
+ last_page = page;
+
+ page->unused_in_this_page = 1;
+ page->unused[0] = entry;
+
+ for (uint16_t i = 1; i < 510; ++i)
+ page->unused[i] = 0;
+
+ }
+
+ void remove_entry(heap_aligned_entry *entry) {
+
+ if (entry->prev)
+ entry->prev->next = entry->next;
+ else
+ first_entry = entry->next;
+ if (entry->next)
+ entry->next->prev = entry->prev;
+ else
+ last_entry = entry->prev;
+
+ mark_entry_unused(entry);
+
+ }
+
+ heap_aligned_entry *get_new_entry() {
+
+ for (unused_heap_entries_page *page = last_page; page != 0; page = page->prev) {
+ if (page->unused_in_this_page == 0)
+ continue;
+ for (uint16_t i = 0; i < 510; ++i)
+ if (page->unused[i] != 0) {
+ heap_aligned_entry *entry = page->unused[i];
+ page->unused[i] = 0;
+ --page->unused_in_this_page;
+ return entry;
+ }
+ }
+
+ heap_aligned_entry *new_entries = (heap_aligned_entry *)euler::syscall::get_new_pages(1);
+
+ for (uint8_t i = 1; i < 128; ++i)
+ mark_entry_unused(new_entries + i);
+
+ return new_entries;
+
+ }
+
+ void *get_block(size_t length) {
+
+ for (heap_aligned_entry *entry = first_entry; entry != 0; entry = entry->next) {
+ if (entry->length == length) {
+ void *start = (void *)entry->start_vaddr;
+ remove_entry(entry);
+ return start;
+ }
+ if (entry->length > length) {
+ void *start = (void *)entry->start_vaddr;
+ entry->start_vaddr += length;
+ entry->length -= length;
+ return start;
+ }
+ }
+
+ size_t pages = (length - 1) / 4096 + 1;
+ void *new_memory = euler::syscall::get_new_pages(pages);
+ if (pages * 4096 != length)
+ return_block((uint8_t *)new_memory + length, pages * 4096 - length);
+ return new_memory;
+
+ }
+
+ void return_block(void *start, size_t length) {
+
+ heap_aligned_entry *after = first_entry;
+ while (after != 0 && after->start_vaddr < (size_t)start + length)
+ after = after->next;
+
+ heap_aligned_entry *before;
+ if (after == 0)
+ before = last_entry;
+ else
+ before = after->prev;
+
+ heap_aligned_entry *us;
+
+ if (after && after->start_vaddr == (size_t)start + length) {
+ after->start_vaddr -= length;
+ after->length += length;
+ us = after;
+ }
+
+ else {
+ us = get_new_entry();
+ us->prev = before;
+ us->next = after;
+ us->start_vaddr = (size_t)start;
+ us->length = length;
+ if (before)
+ before->next = us;
+ else
+ first_entry = us;
+ if (after)
+ after->prev = us;
+ else
+ last_entry = us;
+ }
+
+ if (before && before->start_vaddr + before->length == (size_t)start) {
+ us->start_vaddr -= before->length;
+ us->length += before->length;
+ remove_entry(before);
+ }
+
+ }
+
+}
diff --git a/euler/source/io/fclose.cpp b/euler/source/io/fclose.cpp
deleted file mode 100644
index 6f43f85..0000000
--- a/euler/source/io/fclose.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#include <cstdio>
-
-namespace std {
-
- int fclose(FILE *stream) {
- delete stream;
- return 0;
- }
-
-}
diff --git a/euler/source/io/fopen.cpp b/euler/source/io/fopen.cpp
deleted file mode 100644
index 8d47bf0..0000000
--- a/euler/source/io/fopen.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <stdint.h>
-#include <cstring>
-#include <cstdio>
-
-namespace std {
-
- FILE *fopen(const char *filename, const char *mode) {
-
- bool read = false;
- bool write = false;
- bool append = false;
- bool extended = false;
- bool create = false;
-
- for (const char *p = mode; *p; ++p)
- switch (*p) {
- case 'r':
- read = true;
- continue;
- case 'w':
- write = true;
- continue;
- case 'a':
- append = true;
- continue;
- case '+':
- extended = true;
- continue;
- case 'x':
- create = true;
- continue;
- default:
- continue;
- }
-
- __euler_stream_handle handle;
- __euler_stream_result res = __euler_open_file(
- filename, strlen(filename), handle, write || append, create);
-
- if (res != __EULER_SR_SUCCESS)
- return 0;
-
- euler::file_stream *f = new euler::file_stream(handle, read || extended,
- write || extended, write && !append, append);
-
- if (f->good)
- return f;
-
- delete f;
- return 0;
-
- }
-
-}
diff --git a/euler/source/io/fread.cpp b/euler/source/io/fread.cpp
deleted file mode 100644
index e2d05b6..0000000
--- a/euler/source/io/fread.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include <cstdio>
-
-namespace std {
-
- size_t fread(void *buffer, size_t size, size_t count, FILE *stream) {
- return stream->try_read(buffer, size * count) ? count : 0;
- }
-
-}
diff --git a/euler/source/io/fseek.cpp b/euler/source/io/fseek.cpp
deleted file mode 100644
index 3254468..0000000
--- a/euler/source/io/fseek.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include <cstdio>
-
-namespace std {
-
- int fseek(FILE *stream, long offset, int origin) {
- if (origin < 0 || origin > 2)
- return 1;
- return stream->try_seek((__euler_seek_from)origin, offset) ? 0 : 2;
- }
-
-}
diff --git a/euler/source/memory/delete.cpp b/euler/source/memory/delete.cpp
deleted file mode 100644
index e4cc288..0000000
--- a/euler/source/memory/delete.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include <euler/heap.hpp>
-
-void operator delete(void *ptr) {
- euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
-}
-
-void operator delete(void *ptr, uint64_t) {
- euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
-}
-
-void operator delete[](void *ptr) {
- euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
-}
-
-void operator delete[](void *ptr, uint64_t) {
- euler::dealloc((uint8_t *)ptr - 8, *(uint64_t *)((uint8_t *)ptr - 8));
-}
diff --git a/euler/source/memory/new.cpp b/euler/source/memory/new.cpp
deleted file mode 100644
index 931328f..0000000
--- a/euler/source/memory/new.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <euler/heap.hpp>
-
-void *operator new(uint64_t size) {
- void *ptr = euler::alloc(size + 8);
- *(uint64_t *)ptr = size + 8;
- return (uint8_t *)ptr + 8;
-}
-
-void *operator new[](uint64_t size) {
- void *ptr = euler::alloc(size + 8);
- *(uint64_t *)ptr = size + 8;
- return (uint8_t *)ptr + 8;
-}
diff --git a/euler/source/std/cctype.cpp b/euler/source/std/cctype.cpp
new file mode 100644
index 0000000..a35d1a5
--- /dev/null
+++ b/euler/source/std/cctype.cpp
@@ -0,0 +1,7 @@
+#include <cctype>
+
+extern "C" int isspace(int ch) {
+ return
+ ch == ' ' || ch == '\f' || ch == '\n' ||
+ ch == '\r' || ch == '\t' || ch == '\v';
+}
diff --git a/euler/source/std/cstdio.cpp b/euler/source/std/cstdio.cpp
new file mode 100644
index 0000000..8c12a7c
--- /dev/null
+++ b/euler/source/std/cstdio.cpp
@@ -0,0 +1,59 @@
+#include <cstdio>
+
+extern "C" FILE *fopen(const char *filename, const char *mode) {
+
+ bool r = false, w = false, a = false, p = false, x = false;
+ for (size_t i = 0; mode[i] != '\0'; ++i)
+ if (mode[i] == 'r') r = true;
+ else if (mode[i] == 'w') w = true;
+ else if (mode[i] == 'a') a = true;
+ else if (mode[i] == 'p') p = true;
+ else if (mode[i] == 'x') x = true;
+
+ euler::syscall::stream_handle handle;
+ if (euler::syscall::open_file(filename, !r, x, handle) !=
+ euler::syscall::stream_result::success)
+ return 0;
+
+ if (w && euler::syscall::set_stream_length(handle, 0) !=
+ euler::syscall::stream_result::success)
+ return 0;
+
+ if (a && euler::syscall::seek_stream(
+ handle, euler::syscall::seek_from::end, 0) !=
+ euler::syscall::stream_result::success) {
+ euler::syscall::close_stream(handle);
+ return 0;
+ }
+
+ uint64_t length;
+ if (euler::syscall::get_stream_length(handle, length) !=
+ euler::syscall::stream_result::success) {
+ euler::syscall::close_stream(handle);
+ return 0;
+ }
+
+ return new euler::file_stream(handle, r || p, length, a ? length : 0);
+
+}
+
+extern "C" void fclose(FILE *stream) {
+ stream->close();
+ delete stream;
+}
+
+extern "C" int fseek(FILE *stream, long offset, int origin) {
+
+ if (origin < 0 || origin > 2)
+ return -1;
+
+ return (int)stream->seek((euler::syscall::seek_from)origin, offset);
+
+}
+
+extern "C" size_t fread(
+ void *buffer, size_t size, size_t count, FILE *stream) {
+
+ return (stream->read(size * count, buffer).first - 1) / size + 1;
+
+}
diff --git a/euler/source/std/cstdlib.cpp b/euler/source/std/cstdlib.cpp
new file mode 100644
index 0000000..cfb4b48
--- /dev/null
+++ b/euler/source/std/cstdlib.cpp
@@ -0,0 +1,19 @@
+#include <euler/heap.hpp>
+#include <cstdlib>
+
+extern "C" [[noreturn]] void abort() noexcept {
+ //TODO
+ while (1)
+ ;
+}
+
+extern "C" void *malloc(size_t size) {
+ size_t *block = (size_t *)euler::heap::get_block(size + 8);
+ *block = size;
+ return block + 1;
+}
+
+extern "C" void free(void *ptr) {
+ size_t *block = (size_t *)ptr - 1;
+ euler::heap::return_block(block, *block + 8);
+}
diff --git a/euler/source/std/cstring.cpp b/euler/source/std/cstring.cpp
new file mode 100644
index 0000000..3e5a56c
--- /dev/null
+++ b/euler/source/std/cstring.cpp
@@ -0,0 +1,36 @@
+#include <cstring>
+
+extern "C" void *memset(void *dest, int ch, size_t count) {
+ unsigned char c = static_cast<unsigned char>(ch);
+ unsigned char *d = (unsigned char *)dest;
+ for (size_t i = 0; i < count; ++i)
+ d[i] = c;
+ return dest;
+}
+
+extern "C" void *memcpy(void *dest, const void *src, size_t count) {
+ unsigned char *d = (unsigned char *)dest;
+ const unsigned char *s = (const unsigned char *)src;
+ for (size_t i = 0; i < count; ++i)
+ d[i] = s[i];
+ return dest;
+}
+
+extern "C" int strcmp(const char *lhs, const char *rhs) {
+ const unsigned char *l = (const unsigned char *)lhs;
+ const unsigned char *r = (const unsigned char *)rhs;
+ while (*l == *r) {
+ if (*l == 0)
+ return 0;
+ ++l;
+ ++r;
+ }
+ return *l < *r ? -1 : 1;
+}
+
+extern "C" size_t strlen(const char *str) {
+ size_t len = 0;
+ while (str[len] != '\0')
+ ++len;
+ return len;
+}
diff --git a/euler/source/std/string.cpp b/euler/source/std/string.cpp
new file mode 100644
index 0000000..31c47a5
--- /dev/null
+++ b/euler/source/std/string.cpp
@@ -0,0 +1,86 @@
+#include <cctype>
+#include <string>
+
+namespace std {
+
+ int stoi(const std::string &str, size_t *pos, int base) {
+ //TODO: exceptions
+
+ size_t i = 0;
+ while (isspace(str[i]))
+ ++i;
+
+ bool is_negative = false;
+ if (str[i] == '-') {
+ is_negative = true;
+ ++i;
+ }
+ else if (str[i] == '+')
+ ++i;
+
+ if ((base == 16 || base == 0) && str[i] == '0' &&
+ (str[i + 1] == 'x' || str[i + 1] == 'X')) {
+ base = 16;
+ i += 2;
+ }
+
+ else if ((base == 8 || base == 0) && str[i] == '0') {
+ base = 8;
+ ++i;
+ }
+
+ else if (base == 0)
+ base = 10;
+
+ int value = 0;
+
+ while (true) {
+ char c = str[i];
+ if (c >= '0' && c < '0' + base)
+ value = value * base + c - '0';
+ else if (c >= 'a' && c < 'a' + base - 10)
+ value = value * base + c - 'a' + 10;
+ else if (c >= 'A' && c < 'A' + base - 10)
+ value = value * base + c - 'A' + 10;
+ else
+ break;
+ }
+
+ if (pos != 0)
+ *pos = i;
+
+ return is_negative ? -value : value;
+
+ }
+
+ std::string to_string(int value) {
+
+ int max_place = 1;
+ int places = 1;
+ while (max_place <= value / 10) {
+ max_place *= 10;
+ ++places;
+ }
+
+ std::string s;
+ s.resize(places);
+
+ for (int i = 0; i < places; ++i) {
+ s[i] = (value / max_place) % 10 + '0';
+ max_place /= 10;
+ }
+
+ return s;
+
+ }
+
+ std::string operator +(std::string &&lhs, std::string &&rhs) {
+ std::string s = std::move(lhs);
+ s.resize(lhs.size() + rhs.size());
+ for (size_t i = 0; i < rhs.size(); ++i)
+ s[lhs.size() + i] = rhs[i];
+ rhs.clear();
+ return s;
+ }
+
+}
diff --git a/euler/source/stream.cpp b/euler/source/stream.cpp
new file mode 100644
index 0000000..faf2907
--- /dev/null
+++ b/euler/source/stream.cpp
@@ -0,0 +1,106 @@
+#include <euler/stream.hpp>
+#include <cstring>
+
+namespace euler {
+
+ file_stream::file_stream(
+ syscall::stream_handle handle, bool may_read,
+ uint64_t length, uint64_t position)
+ : handle(handle), may_read(may_read), buffer_loaded(false),
+ length(length), position(position) {}
+
+ syscall::stream_result file_stream::seek(
+ syscall::seek_from from, int64_t offset) {
+
+ int64_t new_position = offset +
+ (from == syscall::seek_from::beginning ? 0 :
+ from == syscall::seek_from::end ? length : position);
+
+ if (new_position < 0 || (uint64_t)new_position > length)
+ return syscall::stream_result::out_of_bounds;
+
+ position = new_position;
+ return syscall::stream_result::success;
+
+ }
+
+ std::pair<uint64_t, syscall::stream_result>
+ file_stream::read(uint64_t bytes, void *into) {
+
+ if (!may_read)
+ return {0, syscall::stream_result::not_readable};
+
+ uint64_t have_read = 0;
+ syscall::stream_result result = syscall::stream_result::success;
+
+ uint64_t end = position + bytes;
+
+ if (end > length) {
+ end = length;
+ result = syscall::stream_result::out_of_bounds;
+ }
+
+ uint64_t block_start = (position / 1024) * 1024;
+
+ while (position < end) {
+
+ uint64_t length_in_this_block =
+ std::min(end, block_start + 1024) - position;
+
+ if (buffer_loaded && buffer_start == block_start)
+ memcpy(into, buffer + position - block_start, length_in_this_block);
+
+ else if (length_in_this_block == 1024) {
+
+ syscall::stream_result seek_result =
+ syscall::seek_stream(
+ handle, syscall::seek_from::beginning, block_start);
+ if (seek_result != syscall::stream_result::success)
+ return {have_read, seek_result};
+
+ syscall::stream_result read_result =
+ syscall::read_from_stream(handle, 1024, into);
+ if (read_result != syscall::stream_result::success)
+ return {have_read, read_result};
+
+ }
+
+ else {
+
+ syscall::stream_result seek_result =
+ syscall::seek_stream(
+ handle, syscall::seek_from::beginning, block_start);
+ if (seek_result != syscall::stream_result::success)
+ return {have_read, seek_result};
+
+ uint64_t buffer_length = std::min(1024UL, length - block_start);
+
+ syscall::stream_result read_result =
+ syscall::read_from_stream(handle, buffer_length, buffer);
+ if (read_result != syscall::stream_result::success) {
+ buffer_loaded = false;
+ return {have_read, read_result};
+ }
+
+ buffer_loaded = true;
+ buffer_start = block_start;
+ memcpy(into, buffer + position - block_start, length_in_this_block);
+
+ }
+
+ into = (uint8_t *)into + length_in_this_block;
+ have_read += length_in_this_block;
+ position += length_in_this_block;
+ block_start += 1024;
+
+ }
+
+ return {have_read, result};
+
+ }
+
+ void file_stream::close() {
+ syscall::close_stream(handle);
+ }
+
+}
diff --git a/euler/source/strings/memcpy.cpp b/euler/source/strings/memcpy.cpp
deleted file mode 100644
index d5a1d6c..0000000
--- a/euler/source/strings/memcpy.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <stdint.h>
-#include <cstring>
-
-namespace std {
-
- void *memcpy(void *dest, const void *src, size_t count) {
- uint8_t *d8 = (uint8_t *)dest;
- const uint8_t *s8 = (const uint8_t *)src;
- for (size_t i = 0; i < count; ++i)
- d8[i] = s8[i];
- return dest;
- }
-
-}
diff --git a/euler/source/strings/strlen.cpp b/euler/source/strings/strlen.cpp
deleted file mode 100644
index 7a6fe2a..0000000
--- a/euler/source/strings/strlen.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <cstring>
-
-namespace std {
-
- size_t strlen(const char *str) {
- size_t len = 0;
- while (str[len])
- ++len;
- return len;
- }
-
-}
diff --git a/euler/source/syscall.asm b/euler/source/syscall.asm
new file mode 100644
index 0000000..d4515bb
--- /dev/null
+++ b/euler/source/syscall.asm
@@ -0,0 +1,32 @@
+bits 64
+
+section .text
+
+global __euler_do_syscall
+__euler_do_syscall:
+
+ push rdi
+ push rsi
+ push rdx
+ push rcx
+
+ mov rax, qword [rdi]
+ mov rdi, qword [rsi]
+ mov rsi, qword [rdx]
+ mov rdx, qword [rcx]
+
+ syscall
+
+ pop rcx
+ mov qword [rcx], rdx
+
+ pop rdx
+ mov qword [rdx], rsi
+
+ pop rsi
+ mov qword [rsi], rdi
+
+ pop rdi
+ mov qword [rdi], rax
+
+ ret
diff --git a/euler/source/syscall.cpp b/euler/source/syscall.cpp
new file mode 100644
index 0000000..b3ed3a8
--- /dev/null
+++ b/euler/source/syscall.cpp
@@ -0,0 +1,397 @@
+#include <euler/syscall.hpp>
+
+extern "C" void __euler_do_syscall(
+ uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
+
+namespace euler::syscall {
+
+ encoded_color encode_color(
+ uint8_t r, uint8_t g, uint8_t b) {
+
+ uint64_t rax = 0;
+ uint64_t rdi = (uint32_t)r | ((uint32_t)g << 8) | ((uint32_t)b << 16);
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (encoded_color)(rax & 0xffffffff);
+
+ }
+
+ void get_framebuffer(
+ encoded_color *&buffer_out, uint32_t &width_out,
+ uint32_t &height_out, uint32_t &pitch_out) {
+
+ uint64_t rax = 1;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ buffer_out = (encoded_color *)rax;
+ width_out = rdi & 0xffffffff;
+ height_out = rdi >> 32;
+ pitch_out = rsi & 0xffffffff;
+
+ }
+
+ stream_result open_file(
+ const std::string &file_path, bool allow_creation,
+ bool only_allow_creation, stream_handle &handle_out) {
+
+ uint64_t rax = 2;
+ uint64_t rdi = (uint64_t)file_path.data();
+ uint64_t rsi = file_path.size();
+ uint64_t rdx =
+ ( allow_creation ? 0x1 : 0x0) |
+ (only_allow_creation ? 0x2 : 0x0);
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ handle_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ [[noreturn]] void end_this_thread(int32_t exit_code) {
+
+ uint64_t rax = 3;
+ uint64_t rdi = (uint32_t)exit_code;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ __builtin_unreachable();
+
+ }
+
+ void *get_new_pages(uint64_t n_pages) {
+
+ uint64_t rax = 4;
+ uint64_t rdi = n_pages;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (void *)rax;
+
+ }
+
+ std::variant<mouse_packet, key_packet> get_input_packet() {
+
+ uint64_t rax = 5;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ if (rax & 0x80)
+ return (mouse_packet){
+ . left_button_down = (rax & 0x01) != 0,
+ . right_button_down = (rax & 0x02) != 0,
+ .middle_button_down = (rax & 0x04) != 0,
+ .x_changed = (int16_t)(rdi & 0xffff),
+ .y_changed = (int16_t)(rsi & 0xffff)
+ };
+
+ return (key_packet){
+ .was_key_up_event = (rdi & 0x40000) != 0,
+ . num_lock = (rdi & 0x20000) != 0,
+ . caps_lock = (rdi & 0x10000) != 0,
+ . right_win = (rdi & 0x8000) != 0,
+ . left_win = (rdi & 0x4000) != 0,
+ . right_alt = (rdi & 0x2000) != 0,
+ . left_alt = (rdi & 0x1000) != 0,
+ . right_ctrl = (rdi & 0x800) != 0,
+ . left_ctrl = (rdi & 0x400) != 0,
+ . right_shift = (rdi & 0x200) != 0,
+ . left_shift = (rdi & 0x100) != 0,
+ . key_code = (uint8_t)(rdi & 0xff)
+ };
+
+ }
+
+ void create_private_socket(
+ stream_handle &end_1_out, stream_handle &end_2_out) {
+
+ uint64_t rax = 6;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ end_1_out = rax;
+ end_2_out = rdi;
+
+ }
+
+ stream_result create_socket_listener(
+ const std::string &id, listener_handle &handle_out) {
+
+ uint64_t rax = 7;
+ uint64_t rdi = (uint64_t)id.data();
+ uint64_t rsi = id.size();
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ handle_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ void stop_socket_listener(listener_handle handle) {
+
+ uint64_t rax = 8;
+ uint64_t rdi = handle;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ }
+
+ stream_result accept_socket_connection(
+ listener_handle listener, stream_handle &stream_out) {
+
+ uint64_t rax = 9;
+ uint64_t rdi = listener;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ stream_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ stream_result connect_to_socket(
+ const std::string &id, stream_handle &handle_out) {
+
+ uint64_t rax = 10;
+ uint64_t rdi = (uint64_t)id.data();
+ uint64_t rsi = id.size();
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ handle_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ void close_stream(stream_handle handle) {
+
+ uint64_t rax = 11;
+ uint64_t rdi = handle;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ }
+
+ stream_result seek_stream(
+ stream_handle handle, seek_from from, int64_t offset) {
+
+ uint64_t rax = 12;
+ uint64_t rdi = (uint64_t)handle;
+ uint64_t rsi = (uint8_t)from;
+ uint64_t rdx = (uint64_t)offset;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (stream_result)rax;
+
+ }
+
+ stream_result read_from_stream(
+ stream_handle handle, uint64_t bytes, void *into) {
+
+ uint64_t rax = 13;
+ uint64_t rdi = (uint64_t)handle;
+ uint64_t rsi = bytes;
+ uint64_t rdx = (uint64_t)into;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (stream_result)rax;
+
+ }
+
+ stream_result write_to_stream(
+ stream_handle handle, uint64_t bytes, const void *from) {
+
+ uint64_t rax = 14;
+ uint64_t rdi = (uint64_t)handle;
+ uint64_t rsi = bytes;
+ uint64_t rdx = (uint64_t)from;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (stream_result)rax;
+
+ }
+
+ stream_result get_stream_length(
+ stream_handle handle, uint64_t &length_out) {
+
+ uint64_t rax = 15;
+ uint64_t rdi = (uint64_t)handle;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ length_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ stream_result start_process(
+ const std::string &file_path,
+ const std::vector<std::pair<std::string, std::string>> &environment_variables,
+ const std::vector<std::pair<stream_handle, stream_result>> &gifted_streams,
+ process_handle &handle_out) {
+
+ std::vector<uint64_t> ev_structs(environment_variables.size() * 4);
+ for (size_t i = 0; i < environment_variables.size(); ++i) {
+ ev_structs[i * 4] = environment_variables[i]. first.size();
+ ev_structs[i * 4 + 1] = (uint64_t)environment_variables[i]. first.data();
+ ev_structs[i * 4 + 2] = environment_variables[i].second.size();
+ ev_structs[i * 4 + 3] = (uint64_t)environment_variables[i].second.data();
+ }
+
+ std::vector<uint64_t> gs_structs(gifted_streams.size() * 2);
+ for (size_t i = 0; i < environment_variables.size(); ++i) {
+ gs_structs[i * 2] = (uint64_t)gifted_streams[i]. first;
+ gs_structs[i * 2 + 1] = (uint64_t)gifted_streams[i].second;
+ }
+
+ uint64_t psi_struct[] = {
+ file_path.size(), (uint64_t) file_path.data(),
+ environment_variables.size(), (uint64_t)ev_structs.data(),
+ gifted_streams.size(), (uint64_t)gs_structs.data()
+ };
+
+ uint64_t rax = 16;
+ uint64_t rdi = (uint64_t)psi_struct;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ handle_out = rdi;
+ return (stream_result)rax;
+
+ }
+
+ [[noreturn]] void end_this_process(int32_t exit_code) {
+
+ uint64_t rax = 17;
+ uint64_t rdi = (uint32_t)exit_code;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ __builtin_unreachable();
+
+ }
+
+ stream_result set_stream_length(
+ stream_handle handle, uint64_t new_length) {
+
+ uint64_t rax = 18;
+ uint64_t rdi = (uint64_t)handle;
+ uint64_t rsi = new_length;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return (stream_result)rax;
+
+ }
+
+ stream_result get_other_end_process_handle(
+ stream_handle stream, process_handle &process_out) {
+
+ uint64_t rax = 19;
+ uint64_t rdi = (uint64_t)stream;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ process_out = (process_handle)rdi;
+ return (stream_result)rax;
+
+ }
+
+ //entry_point must not return
+ void start_thread(void (*entry_point)(uint64_t), uint64_t arg) {
+
+ uint64_t rax = 20;
+ uint64_t rdi = (uint64_t)entry_point;
+ uint64_t rsi = arg;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ }
+
+ //entry_point must not return
+ void start_thread(void (*entry_point)()) {
+
+ uint64_t rax = 20;
+ uint64_t rdi = (uint64_t)entry_point;
+ uint64_t rsi = 0;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ }
+
+ //return value is number of bytes cleared
+ uint64_t clear_socket_read_queue(stream_handle handle) {
+
+ uint64_t rax = 21;
+ uint64_t rdi = handle;
+ uint64_t rsi;
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ return rax;
+
+ }
+
+ //this function has a race condition if the variable is changed
+ //or unset by another thread between the two syscalls.
+ std::optional<std::string> try_get_environment_variable(
+ const std::string &name) {
+
+ uint64_t rax = 22;
+ uint64_t rdi = (uint64_t)name.data();
+ uint64_t rsi = name.size();
+ uint64_t rdx;
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+
+ if (rax == (uint64_t)-1)
+ return {};
+
+ std::string s;
+ s.resize(rax);
+
+ rax = 23;
+ rdi = (uint64_t)name.data();
+ rsi = name.size();
+ rdx = (uint64_t)s.data();
+
+ __euler_do_syscall(rax, rdi, rsi, rdx);
+ //do i need to tell gcc that s is modified?
+
+ return s;
+
+ }
+
+}