123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- #include <stdarg.h>
- #include <stdint.h>
- using size_t = unsigned long;
- #ifdef __x86_64__
- # define GET_BP(base) __asm__("mov %%rbp, %0\n" : "=r"(base));
- # define SET_STACK(base, size) \
- __asm__("mov %0, %%rsp\n" ::"r"(&base[size - 1]));
- #elif __i386__
- # define GET_BP(base) __asm__("mov %%ebp, %0\n" : "=r"(base));
- # define SET_STACK(base, size) \
- __asm__("mov %0, %%esp\n" ::"r"(&base[size - 1]));
- #else
- # error "Architecture not supported"
- #endif
- const auto strlen = [](const char* str) -> const size_t {
- const char* orig_ptr = str;
- while (*str++)
- ;
- return str - orig_ptr;
- };
- const auto not_itoa = [](int num, uint8_t base, bool buffcase) -> char* {
- int i = 30;
- static char buffer[32] = {0};
- if (num == 0) {
- buffer[0] = '0';
- return buffer;
- }
- while (num && i) {
- buffer[i] = buffcase ? "0123456789ABCDEF"[num % base]
- : "0123456789abcdef"[num % base];
- num /= base;
- i--;
- }
- return &buffer[i + 1];
- };
- namespace platform
- {
- using fd_t = unsigned int;
- struct base_platform_controller
- {
- virtual void output(fd_t fd, const char chr) = 0;
- virtual void output(fd_t fd, const char* str) = 0;
- virtual void stop(int exit_code = 0) = 0;
- };
- namespace syscall
- {
- inline int write(fd_t fd, const char* buffer, int size)
- {
- int written;
- #if __x86_64__
- __asm__("syscall\n"
- : "=a"(written)
- : "a"(1), "b"(fd), "m"(buffer), "d"(size));
- #elif __aarch64__
- __asm__(
- "ldr x0, %0\n"
- "ldr x1, %1\n"
- "mov w8, #64\n"
- "svc #0\n" ::"m"(fd),
- "m"(buffer), "m"(size)
- );
- #else
- # error "Unsupported architecture"
- #endif
- return written;
- }
- inline void exit(int exit = 0)
- {
- #if __x86_64__
- __asm__("syscall\n" ::"a"(60), "b"(exit));
- #elif __aarch64__
- # warning \
- "No exit() syscall was defined for this architecture yet. Expect segfaults"
- #else
- # error "Unsupported architecture"
- #endif
- }
- struct platform_controller : base_platform_controller
- {
- void output(fd_t fd, const char chr) override
- {
- syscall::write(fd, &chr, 1);
- }
- void output(fd_t fd, const char* str) override
- {
- syscall::write(fd, str, strlen(str));
- }
- void stop(int exit_code = 0) override { syscall::exit(exit_code); }
- };
- }
- syscall::platform_controller pc;
- }
- namespace io
- {
- using namespace ::platform;
- enum std_fd : fd_t
- {
- STDOUT = 1,
- STDERR,
- STDIN,
- };
- struct base_output
- {
- virtual inline void put(const char chr) const = 0;
- virtual inline void put(const char* str) const = 0;
- virtual inline void put() const = 0;
- };
- namespace printf
- {
- enum
- {
- PRINTF_TYPE_CHAR = 0x00000010,
- PRINTF_TYPE_STR = 0x00000020,
- PRINTF_TYPE_INT = 0x00000030,
- PRINTF_TYPE_UINT = 0x00000040,
- PRINTF_BASE_DEC = 0x0000A000,
- PRINTF_BASE_HEX = 0x0000F000,
- PRINTF_MASK_TYPE = 0x000000F0,
- PRINTF_MASK_CASE = 0x00000100,
- PRINTF_MASK_BASE = 0x0000F000
- };
- void vaprintf(va_list* args, const char* format, const base_output& out)
- {
- const auto vaprintf_parse_args = [](const char* format
- ) -> uint32_t {
- uint32_t flags = 0;
- if (*format == '0')
- format++;
- if (*format == 'c')
- flags |= PRINTF_TYPE_CHAR;
- else if (*format == 's')
- flags |= PRINTF_TYPE_STR;
- else if (*format == 'd') {
- flags |= PRINTF_TYPE_INT;
- flags |= PRINTF_BASE_DEC;
- } else if (*format == 'X') {
- flags |= PRINTF_MASK_CASE;
- flags |= PRINTF_TYPE_UINT;
- flags |= PRINTF_BASE_HEX;
- } else if (*format == 'x') {
- flags |= PRINTF_TYPE_UINT;
- flags |= PRINTF_BASE_HEX;
- }
- format++;
- return flags;
- };
- const auto vaprintf_handle_args = [vaprintf_parse_args](
- va_list* args,
- const char* format,
- const base_output& out
- ) {
- uint32_t flags = vaprintf_parse_args(format);
- int base = (flags & PRINTF_MASK_BASE) >> 12;
- bool buffer_case = flags & PRINTF_MASK_CASE;
-
- base = base == 15 ? 16 : base;
- if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_CHAR)
- out.put(va_arg(*args, int));
- else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_STR)
- out.put(va_arg(*args, const char*));
- else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_UINT)
- out.put(not_itoa(va_arg(*args, uint32_t), base, buffer_case)
- );
- else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_INT)
- out.put(not_itoa(va_arg(*args, int), base, buffer_case));
- };
- while (*format) {
- if (*format == '%') {
- format++;
- vaprintf_handle_args(args, format, out);
- } else {
- out.put(*format);
- }
- format++;
- }
- }
- void out_printf(const base_output& out, const char* format, ...)
- {
- va_list va;
- va_start(va, format);
- vaprintf(&va, format, out);
- va_end(va);
- }
- }
- template<fd_t fd> struct fd_output : base_output
- {
- inline void put(const char chr) const override
- {
- platform::pc.output(fd, chr);
- }
- inline void put(const char* str) const override
- {
- platform::pc.output(fd, str);
- }
- inline void put() const override { platform::pc.output(fd, "\n"); }
- };
- template<typename O> struct formatted_output
- {
- const O output;
- inline void put(const char chr) const { output.put(chr); }
- inline void put(const char* format, ...) const
- {
- va_list va;
- va_start(va, format);
- io::printf::vaprintf(&va, format, output);
- va_end(va);
- }
- inline void put(const bool boolean) const
- {
- output.put(boolean ? "(true)" : "(false)");
- }
- inline void put() const { output.put(); }
- };
- }
- namespace error
- {
- const io::formatted_output<io::fd_output<io::STDERR>> err;
- struct stack_slice
- {
- stack_slice* bp;
- uintptr_t ip;
- inline void print() { err.put(" - BP = 0x%x; IP = 0x%x\n", bp, ip); }
- static inline void trace(int trace_limit)
- {
- stack_slice* base;
- GET_BP(base);
- err.put("stacktrace:\n");
- for (int count = 0; base && count < trace_limit; count++) {
- base->print();
- base = base->bp;
- }
- }
- static inline void trace()
- {
- stack_slice* base;
- GET_BP(base);
- err.put("stacktrace:\n");
- for (int count = 0; base && count < 100; count++) {
- base->print();
- base = base->bp;
- }
- }
- };
- struct error_manager
- {
- inline void exit_with_message(const char* str, int code = 0) const
- {
- err.put(str);
- err.put();
- stack_slice().trace();
- this->exit(code);
- }
- inline void print(const char* str) const
- {
- err.put(str);
- err.put();
- stack_slice().trace();
- }
- inline void exit() const { platform::pc.stop(0); }
- inline void exit(int code = 0) const { platform::pc.stop(code); }
- };
- struct error
- {
- const char* message;
- const error_manager em;
- explicit error(const char* msg)
- : message(msg),
- em()
- {
- }
- inline void issue() const { em.exit_with_message(message, 1); }
- inline void print() const { em.print(message); }
- };
- }
- namespace containers
- {
- template<size_t S> struct bounds_checker
- {
- [[nodiscard]] inline bool check(size_t index, bool strict = true) const
- {
- if (index >= S) {
- if (strict)
- error::error("Caught potential OOB situation").issue();
- else
- return false;
- } else {
- return true;
- }
- return false;
- }
- };
- template<typename T> struct iterable
- {
- virtual inline const T* begin() const = 0;
- virtual inline const T* end() const = 0;
- [[nodiscard]] virtual inline const size_t length() const = 0;
- };
- template<typename T> struct base_array : iterable<T>
- {
- [[nodiscard]] virtual inline const T get(const uintptr_t index
- ) const = 0;
- [[nodiscard]] virtual inline const T operator[](const size_t index
- ) const = 0;
- };
- template<typename T, size_t S> class array : base_array<T>
- {
- private:
- T contents[S];
- bounds_checker<S> bc;
- public:
- explicit array(const T* contents)
- {
- for (size_t i = 0; i < S && bc.check(i); i++)
- this->contents[i] = contents[i];
- }
- [[nodiscard]] inline const T get(uintptr_t index) const override
- {
- if (bc.check(index))
- return this->contents[index];
- else
- return -1;
- }
- [[nodiscard]] inline const T operator[](const size_t index
- ) const override
- {
- return this->get(index);
- };
- inline void set(uintptr_t index, const T& data)
- {
- if (bc.check(index))
- this->contents[index] = data;
- }
- [[nodiscard]] inline const size_t length() const override { return S; }
- inline const T* begin() const override { return &this->contents[0]; };
- inline const T* end() const override { return &this->contents[S]; };
- };
- class string : base_array<char>
- {
- private:
- char str[8192];
- bounds_checker<8192> bc;
- public:
- explicit string()
- : str()
- {
- }
- explicit string(const char* str)
- {
- for (size_t i = 0; i < strlen(str) && bc.check(i); i++)
- this->str[i] = str[i];
- }
- [[nodiscard]] inline const char* cstr() const { return this->str; }
- inline const char* begin() const override { return this->str; }
- inline const char* end() const override
- {
- return &this->str[this->length() - 1];
- }
- [[nodiscard]] inline const size_t length() const override
- {
- return strlen(this->str);
- }
- [[nodiscard]] inline const char get(const uintptr_t index
- ) const override
- {
- if (bc.check(index) && index < this->length())
- return this->str[index];
- else
- return 0;
- }
- [[nodiscard]] inline const char operator[](const size_t index
- ) const override
- {
- return this->get(index);
- }
- };
- template<typename A, typename B> struct pair
- {
- A first;
- B second;
- };
- }
- namespace cpp_runtime
- {
- extern "C" void __stack_chk_fail()
- {
- error::error("Stack smashed XwX").issue();
- }
- extern "C" void __cxa_pure_virtual()
- {
- error::error("Pure virtual function cannot be called XwX").print();
- }
- }
- namespace program
- {
- error::stack_slice stack[8192] {0};
- struct combined_output
- {
- const io::formatted_output<io::fd_output<io::STDOUT>> stdout;
- const io::formatted_output<io::fd_output<io::STDERR>> stderr;
- inline void put(const char chr) const { stdout.put(chr); }
- inline void put(const char* format, ...) const
- {
- va_list va;
- va_start(va, format);
- io::printf::vaprintf(&va, format, stdout.output);
- va_end(va);
- stdout.put(format);
- }
- inline void put(const bool boolean) const
- {
- stdout.put(boolean ? "(true)" : "(false)");
- }
- inline void put() const { stdout.put(); }
- inline void err_put(const char chr) const { stderr.put(chr); }
- inline void err_put(const char* format, ...) const
- {
- va_list va;
- va_start(va, format);
- io::printf::vaprintf(&va, format, stderr.output);
- va_end(va);
- }
- inline void err_put(const bool boolean) const
- {
- stderr.put(boolean ? "(true)" : "(false)");
- }
- inline void err_put() const { stderr.put(); }
- };
- struct base_program
- {
- const combined_output out;
- [[nodiscard]] virtual inline const int main() = 0;
- };
- struct prog : base_program
- {
- void print_string(const containers::string& str)
- {
- for (const auto& x : str)
- out.put(x);
- out.put();
- }
- [[nodiscard]] inline const int main() override
- {
- print_string(containers::string("Hello, world!"));
- return 0;
- }
- };
- }
- extern "C" void _start()
- {
-
- SET_STACK(program::stack, 8191);
- platform::pc.stop(program::prog().main());
- }
|