abcd.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. // compile:
  2. // $ g++ -o abcd abcd.cpp -nostdlib -ffreestanding -fno-rtti
  3. //
  4. // license: cc0 1.0 (public domain)
  5. #include <stdarg.h>
  6. #include <stdint.h>
  7. using size_t = unsigned long;
  8. #ifdef __x86_64__
  9. # define GET_BP(base) __asm__("mov %%rbp, %0\n" : "=r"(base));
  10. # define SET_STACK(base, size) \
  11. __asm__("mov %0, %%rsp\n" ::"r"(&base[size - 1]));
  12. #elif __i386__
  13. # define GET_BP(base) __asm__("mov %%ebp, %0\n" : "=r"(base));
  14. # define SET_STACK(base, size) \
  15. __asm__("mov %0, %%esp\n" ::"r"(&base[size - 1]));
  16. #else
  17. # error "Architecture not supported"
  18. #endif
  19. const auto strlen = [](const char* str) -> const size_t {
  20. const char* orig_ptr = str;
  21. while (*str++)
  22. ;
  23. return str - orig_ptr;
  24. };
  25. const auto not_itoa = [](int num, uint8_t base, bool buffcase) -> char* {
  26. int i = 30;
  27. static char buffer[32] = {0};
  28. if (num == 0) {
  29. buffer[0] = '0';
  30. return buffer;
  31. }
  32. while (num && i) {
  33. buffer[i] = buffcase ? "0123456789ABCDEF"[num % base]
  34. : "0123456789abcdef"[num % base];
  35. num /= base;
  36. i--;
  37. }
  38. return &buffer[i + 1];
  39. };
  40. namespace platform
  41. {
  42. using fd_t = unsigned int;
  43. struct base_platform_controller
  44. {
  45. virtual void output(fd_t fd, const char chr) = 0;
  46. virtual void output(fd_t fd, const char* str) = 0;
  47. virtual void stop(int exit_code = 0) = 0;
  48. };
  49. namespace syscall
  50. {
  51. inline int write(fd_t fd, const char* buffer, int size)
  52. {
  53. int written;
  54. #if __x86_64__
  55. __asm__("syscall\n"
  56. : "=a"(written)
  57. : "a"(1), "b"(fd), "m"(buffer), "d"(size));
  58. #elif __aarch64__
  59. __asm__(
  60. "ldr x0, %0\n"
  61. "ldr x1, %1\n"
  62. "mov w8, #64\n"
  63. "svc #0\n" ::"m"(fd),
  64. "m"(buffer), "m"(size)
  65. );
  66. #else
  67. # error "Unsupported architecture"
  68. #endif
  69. return written;
  70. }
  71. inline void exit(int exit = 0)
  72. {
  73. #if __x86_64__
  74. __asm__("syscall\n" ::"a"(60), "b"(exit));
  75. #elif __aarch64__
  76. # warning \
  77. "No exit() syscall was defined for this architecture yet. Expect segfaults"
  78. #else
  79. # error "Unsupported architecture"
  80. #endif
  81. }
  82. struct platform_controller : base_platform_controller
  83. {
  84. void output(fd_t fd, const char chr) override
  85. {
  86. syscall::write(fd, &chr, 1);
  87. }
  88. void output(fd_t fd, const char* str) override
  89. {
  90. syscall::write(fd, str, strlen(str));
  91. }
  92. void stop(int exit_code = 0) override { syscall::exit(exit_code); }
  93. };
  94. }
  95. syscall::platform_controller pc;
  96. }
  97. namespace io
  98. {
  99. using namespace ::platform;
  100. enum std_fd : fd_t
  101. {
  102. STDOUT = 1,
  103. STDERR,
  104. STDIN,
  105. };
  106. struct base_output
  107. {
  108. virtual inline void put(const char chr) const = 0;
  109. virtual inline void put(const char* str) const = 0;
  110. virtual inline void put() const = 0;
  111. };
  112. namespace printf
  113. {
  114. enum
  115. {
  116. PRINTF_TYPE_CHAR = 0x00000010,
  117. PRINTF_TYPE_STR = 0x00000020,
  118. PRINTF_TYPE_INT = 0x00000030,
  119. PRINTF_TYPE_UINT = 0x00000040,
  120. PRINTF_BASE_DEC = 0x0000A000,
  121. PRINTF_BASE_HEX = 0x0000F000,
  122. PRINTF_MASK_TYPE = 0x000000F0,
  123. PRINTF_MASK_CASE = 0x00000100,
  124. PRINTF_MASK_BASE = 0x0000F000
  125. };
  126. void vaprintf(va_list* args, const char* format, const base_output& out)
  127. {
  128. const auto vaprintf_parse_args = [](const char* format
  129. ) -> uint32_t {
  130. uint32_t flags = 0;
  131. if (*format == '0')
  132. format++;
  133. if (*format == 'c')
  134. flags |= PRINTF_TYPE_CHAR;
  135. else if (*format == 's')
  136. flags |= PRINTF_TYPE_STR;
  137. else if (*format == 'd') {
  138. flags |= PRINTF_TYPE_INT;
  139. flags |= PRINTF_BASE_DEC;
  140. } else if (*format == 'X') {
  141. flags |= PRINTF_MASK_CASE;
  142. flags |= PRINTF_TYPE_UINT;
  143. flags |= PRINTF_BASE_HEX;
  144. } else if (*format == 'x') {
  145. flags |= PRINTF_TYPE_UINT;
  146. flags |= PRINTF_BASE_HEX;
  147. }
  148. format++;
  149. return flags;
  150. };
  151. const auto vaprintf_handle_args = [vaprintf_parse_args](
  152. va_list* args,
  153. const char* format,
  154. const base_output& out
  155. ) {
  156. uint32_t flags = vaprintf_parse_args(format);
  157. int base = (flags & PRINTF_MASK_BASE) >> 12;
  158. bool buffer_case = flags & PRINTF_MASK_CASE;
  159. /* 16 in flags becomes 15, so we need to set 16 */
  160. base = base == 15 ? 16 : base;
  161. if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_CHAR)
  162. out.put(va_arg(*args, int));
  163. else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_STR)
  164. out.put(va_arg(*args, const char*));
  165. else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_UINT)
  166. out.put(not_itoa(va_arg(*args, uint32_t), base, buffer_case)
  167. );
  168. else if ((flags & PRINTF_MASK_TYPE) == PRINTF_TYPE_INT)
  169. out.put(not_itoa(va_arg(*args, int), base, buffer_case));
  170. };
  171. while (*format) {
  172. if (*format == '%') {
  173. format++;
  174. vaprintf_handle_args(args, format, out);
  175. } else {
  176. out.put(*format);
  177. }
  178. format++;
  179. }
  180. }
  181. void out_printf(const base_output& out, const char* format, ...)
  182. {
  183. va_list va;
  184. va_start(va, format);
  185. vaprintf(&va, format, out);
  186. va_end(va);
  187. }
  188. }
  189. template<fd_t fd> struct fd_output : base_output
  190. {
  191. inline void put(const char chr) const override
  192. {
  193. platform::pc.output(fd, chr);
  194. }
  195. inline void put(const char* str) const override
  196. {
  197. platform::pc.output(fd, str);
  198. }
  199. inline void put() const override { platform::pc.output(fd, "\n"); }
  200. };
  201. template<typename O> struct formatted_output
  202. {
  203. const O output;
  204. inline void put(const char chr) const { output.put(chr); }
  205. inline void put(const char* format, ...) const
  206. {
  207. va_list va;
  208. va_start(va, format);
  209. io::printf::vaprintf(&va, format, output);
  210. va_end(va);
  211. }
  212. inline void put(const bool boolean) const
  213. {
  214. output.put(boolean ? "(true)" : "(false)");
  215. }
  216. inline void put() const { output.put(); }
  217. };
  218. }
  219. namespace error
  220. {
  221. const io::formatted_output<io::fd_output<io::STDERR>> err;
  222. struct stack_slice
  223. {
  224. stack_slice* bp;
  225. uintptr_t ip;
  226. inline void print() { err.put(" - BP = 0x%x; IP = 0x%x\n", bp, ip); }
  227. static inline void trace(int trace_limit)
  228. {
  229. stack_slice* base;
  230. GET_BP(base);
  231. err.put("stacktrace:\n");
  232. for (int count = 0; base && count < trace_limit; count++) {
  233. base->print();
  234. base = base->bp;
  235. }
  236. }
  237. static inline void trace()
  238. {
  239. stack_slice* base;
  240. GET_BP(base);
  241. err.put("stacktrace:\n");
  242. for (int count = 0; base && count < 100; count++) {
  243. base->print();
  244. base = base->bp;
  245. }
  246. }
  247. };
  248. struct error_manager
  249. {
  250. inline void exit_with_message(const char* str, int code = 0) const
  251. {
  252. err.put(str);
  253. err.put();
  254. stack_slice().trace();
  255. this->exit(code);
  256. }
  257. inline void print(const char* str) const
  258. {
  259. err.put(str);
  260. err.put();
  261. stack_slice().trace();
  262. }
  263. inline void exit() const { platform::pc.stop(0); }
  264. inline void exit(int code = 0) const { platform::pc.stop(code); }
  265. };
  266. struct error
  267. {
  268. const char* message;
  269. const error_manager em;
  270. explicit error(const char* msg)
  271. : message(msg),
  272. em()
  273. {
  274. }
  275. inline void issue() const { em.exit_with_message(message, 1); }
  276. inline void print() const { em.print(message); }
  277. };
  278. }
  279. namespace containers
  280. {
  281. template<size_t S> struct bounds_checker
  282. {
  283. [[nodiscard]] inline bool check(size_t index, bool strict = true) const
  284. {
  285. if (index >= S) {
  286. if (strict)
  287. error::error("Caught potential OOB situation").issue();
  288. else
  289. return false;
  290. } else {
  291. return true;
  292. }
  293. return false;
  294. }
  295. };
  296. template<typename T> struct iterable
  297. {
  298. virtual inline const T* begin() const = 0;
  299. virtual inline const T* end() const = 0;
  300. [[nodiscard]] virtual inline const size_t length() const = 0;
  301. };
  302. template<typename T> struct base_array : iterable<T>
  303. {
  304. [[nodiscard]] virtual inline const T get(const uintptr_t index
  305. ) const = 0;
  306. [[nodiscard]] virtual inline const T operator[](const size_t index
  307. ) const = 0;
  308. };
  309. template<typename T, size_t S> class array : base_array<T>
  310. {
  311. private:
  312. T contents[S];
  313. bounds_checker<S> bc;
  314. public:
  315. explicit array(const T* contents)
  316. {
  317. for (size_t i = 0; i < S && bc.check(i); i++)
  318. this->contents[i] = contents[i];
  319. }
  320. [[nodiscard]] inline const T get(uintptr_t index) const override
  321. {
  322. if (bc.check(index))
  323. return this->contents[index];
  324. else
  325. return -1;
  326. }
  327. [[nodiscard]] inline const T operator[](const size_t index
  328. ) const override
  329. {
  330. return this->get(index);
  331. };
  332. inline void set(uintptr_t index, const T& data)
  333. {
  334. if (bc.check(index))
  335. this->contents[index] = data;
  336. }
  337. [[nodiscard]] inline const size_t length() const override { return S; }
  338. inline const T* begin() const override { return &this->contents[0]; };
  339. inline const T* end() const override { return &this->contents[S]; };
  340. };
  341. class string : base_array<char>
  342. {
  343. private:
  344. char str[8192];
  345. bounds_checker<8192> bc;
  346. public:
  347. explicit string()
  348. : str()
  349. {
  350. }
  351. explicit string(const char* str)
  352. {
  353. for (size_t i = 0; i < strlen(str) && bc.check(i); i++)
  354. this->str[i] = str[i];
  355. }
  356. [[nodiscard]] inline const char* cstr() const { return this->str; }
  357. inline const char* begin() const override { return this->str; }
  358. inline const char* end() const override
  359. {
  360. return &this->str[this->length() - 1];
  361. }
  362. [[nodiscard]] inline const size_t length() const override
  363. {
  364. return strlen(this->str);
  365. }
  366. [[nodiscard]] inline const char get(const uintptr_t index
  367. ) const override
  368. {
  369. if (bc.check(index) && index < this->length())
  370. return this->str[index];
  371. else
  372. return 0;
  373. }
  374. [[nodiscard]] inline const char operator[](const size_t index
  375. ) const override
  376. {
  377. return this->get(index);
  378. }
  379. };
  380. template<typename A, typename B> struct pair
  381. {
  382. A first;
  383. B second;
  384. };
  385. }
  386. namespace cpp_runtime
  387. {
  388. extern "C" void __stack_chk_fail()
  389. {
  390. error::error("Stack smashed XwX").issue();
  391. }
  392. extern "C" void __cxa_pure_virtual()
  393. {
  394. error::error("Pure virtual function cannot be called XwX").print();
  395. }
  396. }
  397. namespace program
  398. {
  399. error::stack_slice stack[8192] {0};
  400. struct combined_output
  401. {
  402. const io::formatted_output<io::fd_output<io::STDOUT>> stdout;
  403. const io::formatted_output<io::fd_output<io::STDERR>> stderr;
  404. inline void put(const char chr) const { stdout.put(chr); }
  405. inline void put(const char* format, ...) const
  406. {
  407. va_list va;
  408. va_start(va, format);
  409. io::printf::vaprintf(&va, format, stdout.output);
  410. va_end(va);
  411. stdout.put(format);
  412. }
  413. inline void put(const bool boolean) const
  414. {
  415. stdout.put(boolean ? "(true)" : "(false)");
  416. }
  417. inline void put() const { stdout.put(); }
  418. inline void err_put(const char chr) const { stderr.put(chr); }
  419. inline void err_put(const char* format, ...) const
  420. {
  421. va_list va;
  422. va_start(va, format);
  423. io::printf::vaprintf(&va, format, stderr.output);
  424. va_end(va);
  425. }
  426. inline void err_put(const bool boolean) const
  427. {
  428. stderr.put(boolean ? "(true)" : "(false)");
  429. }
  430. inline void err_put() const { stderr.put(); }
  431. };
  432. struct base_program
  433. {
  434. const combined_output out;
  435. [[nodiscard]] virtual inline const int main() = 0;
  436. };
  437. struct prog : base_program
  438. {
  439. void print_string(const containers::string& str)
  440. {
  441. for (const auto& x : str)
  442. out.put(x);
  443. out.put();
  444. }
  445. [[nodiscard]] inline const int main() override
  446. {
  447. print_string(containers::string("Hello, world!"));
  448. return 0;
  449. }
  450. };
  451. }
  452. extern "C" void _start()
  453. {
  454. // setup stack properly, for safety!
  455. SET_STACK(program::stack, 8191);
  456. platform::pc.stop(program::prog().main());
  457. }