libc.c (30450B)
1 #include <stddef.h> 2 #include <stdint.h> 3 #include <stdarg.h> 4 #include <time.h> 5 #include <locale.h> 6 7 /* Forward declarations for types used in stubs */ 8 typedef long off_t; 9 #define EOF (-1) 10 11 /* Global errno */ 12 int errno = 0; 13 14 /* ========== String Functions ========== */ 15 16 void *memcpy(void *dest, const void *src, size_t n) { 17 unsigned char *d = dest; 18 const unsigned char *s = src; 19 while (n--) *d++ = *s++; 20 return dest; 21 } 22 23 void *memset(void *s, int c, size_t n) { 24 unsigned char *p = s; 25 while (n--) *p++ = (unsigned char)c; 26 return s; 27 } 28 29 void *memmove(void *dest, const void *src, size_t n) { 30 unsigned char *d = dest; 31 const unsigned char *s = src; 32 if (d < s) { 33 while (n--) *d++ = *s++; 34 } else { 35 d += n; 36 s += n; 37 while (n--) *--d = *--s; 38 } 39 return dest; 40 } 41 42 int memcmp(const void *s1, const void *s2, size_t n) { 43 const unsigned char *p1 = s1, *p2 = s2; 44 while (n--) { 45 if (*p1 != *p2) return *p1 - *p2; 46 p1++; p2++; 47 } 48 return 0; 49 } 50 51 size_t strlen(const char *s) { 52 size_t len = 0; 53 while (*s++) len++; 54 return len; 55 } 56 57 char *strcpy(char *dest, const char *src) { 58 char *ret = dest; 59 while ((*dest++ = *src++)); 60 return ret; 61 } 62 63 char *strncpy(char *dest, const char *src, size_t n) { 64 size_t i; 65 for (i = 0; i < n && src[i] != '\0'; i++) 66 dest[i] = src[i]; 67 for (; i < n; i++) 68 dest[i] = '\0'; 69 return dest; 70 } 71 72 int strcmp(const char *s1, const char *s2) { 73 while (*s1 && (*s1 == *s2)) { 74 s1++; s2++; 75 } 76 return *(unsigned char *)s1 - *(unsigned char *)s2; 77 } 78 79 int strncmp(const char *s1, const char *s2, size_t n) { 80 while (n && *s1 && (*s1 == *s2)) { 81 s1++; s2++; n--; 82 } 83 if (n == 0) return 0; 84 return *(unsigned char *)s1 - *(unsigned char *)s2; 85 } 86 87 char *strchr(const char *s, int c) { 88 while (*s != (char)c) { 89 if (!*s++) return NULL; 90 } 91 return (char *)s; 92 } 93 94 char *strrchr(const char *s, int c) { 95 const char *last = NULL; 96 do { 97 if (*s == (char)c) last = s; 98 } while (*s++); 99 return (char *)last; 100 } 101 102 char *strstr(const char *haystack, const char *needle) { 103 if (!*needle) return (char *)haystack; 104 105 for (; *haystack; haystack++) { 106 const char *h = haystack; 107 const char *n = needle; 108 109 while (*h && *n && (*h == *n)) { 110 h++; 111 n++; 112 } 113 114 if (!*n) return (char *)haystack; 115 } 116 117 return NULL; 118 } 119 120 int tolower(int c) { 121 if (c >= 'A' && c <= 'Z') 122 return c + ('a' - 'A'); 123 return c; 124 } 125 126 int toupper(int c) { 127 if (c >= 'a' && c <= 'z') 128 return c - ('a' - 'A'); 129 return c; 130 } 131 132 /* ========== Memory Allocation ========== */ 133 134 /* 135 * Free-list allocator with block coalescing 136 * Each block has a header with size and free/used flag 137 * Free blocks are linked in a free list for reuse 138 */ 139 140 #define HEAP_SIZE (384 * 1024 * 1024) /* 384 MB heap for LuaJIT + ramdisk + apps */ 141 static uint8_t heap[HEAP_SIZE] __attribute__((aligned(4096))); 142 143 /* Block header - stored before each allocation */ 144 typedef struct block_header { 145 size_t size; /* Size of user data (not including header) */ 146 struct block_header *next_free; /* Next free block (only valid if free) */ 147 uint32_t magic; /* Magic number for validation */ 148 uint32_t is_free; /* 1 if free, 0 if allocated */ 149 } block_header_t; 150 151 #define BLOCK_MAGIC 0xDEADBEEF 152 #define HEADER_SIZE ((sizeof(block_header_t) + 15) & ~15) /* Aligned header size */ 153 #define MIN_BLOCK_SIZE 32 /* Minimum user data size */ 154 155 /* Free list head */ 156 static block_header_t *free_list = NULL; 157 static int heap_initialized = 0; 158 static size_t heap_end = 0; /* Current end of used heap */ 159 160 extern void terminal_writestring(const char *); 161 extern void terminal_putchar(char); 162 163 static void print_hex(unsigned long val) { 164 char buf[16]; 165 int i = 0; 166 if (val == 0) { 167 terminal_putchar('0'); 168 return; 169 } 170 while (val > 0 && i < 16) { 171 int digit = val & 0xF; 172 buf[i++] = (digit < 10) ? '0' + digit : 'a' + digit - 10; 173 val >>= 4; 174 } 175 while (i > 0) terminal_putchar(buf[--i]); 176 } 177 178 /* Initialize heap if needed */ 179 static void heap_init(void) { 180 if (heap_initialized) return; 181 heap_initialized = 1; 182 heap_end = 0; 183 free_list = NULL; 184 } 185 186 /* Get header from user pointer */ 187 static inline block_header_t *get_header(void *ptr) { 188 return (block_header_t *)((uint8_t *)ptr - HEADER_SIZE); 189 } 190 191 /* Get user pointer from header */ 192 static inline void *get_user_ptr(block_header_t *header) { 193 return (void *)((uint8_t *)header + HEADER_SIZE); 194 } 195 196 /* Find a free block that fits, using first-fit strategy */ 197 static block_header_t *find_free_block(size_t size) { 198 block_header_t *curr = free_list; 199 block_header_t *prev = NULL; 200 201 while (curr) { 202 if (curr->size >= size) { 203 /* Remove from free list */ 204 if (prev) { 205 prev->next_free = curr->next_free; 206 } else { 207 free_list = curr->next_free; 208 } 209 curr->next_free = NULL; 210 curr->is_free = 0; 211 return curr; 212 } 213 prev = curr; 214 curr = curr->next_free; 215 } 216 return NULL; 217 } 218 219 /* Allocate a new block from the heap end */ 220 static block_header_t *alloc_new_block(size_t size) { 221 size_t total_size = HEADER_SIZE + size; 222 223 if (heap_end + total_size > HEAP_SIZE) { 224 return NULL; /* Out of memory */ 225 } 226 227 block_header_t *header = (block_header_t *)&heap[heap_end]; 228 heap_end += total_size; 229 230 header->size = size; 231 header->next_free = NULL; 232 header->magic = BLOCK_MAGIC; 233 header->is_free = 0; 234 235 return header; 236 } 237 238 void *malloc(size_t size) { 239 if (size == 0) return NULL; 240 241 heap_init(); 242 243 /* Align size to 16 bytes, with minimum */ 244 size = (size + 15) & ~15; 245 if (size < MIN_BLOCK_SIZE) size = MIN_BLOCK_SIZE; 246 247 /* Try to find a free block first */ 248 block_header_t *header = find_free_block(size); 249 250 if (!header) { 251 /* No suitable free block, allocate new */ 252 header = alloc_new_block(size); 253 if (!header) { 254 terminal_writestring("MALLOC OOM: size="); 255 print_hex(size); 256 terminal_writestring(" heap_end="); 257 print_hex(heap_end); 258 terminal_writestring("\n"); 259 return NULL; 260 } 261 } 262 263 void *ptr = get_user_ptr(header); 264 memset(ptr, 0, header->size); /* Zero initialize */ 265 return ptr; 266 } 267 268 void free(void *ptr) { 269 if (!ptr) return; 270 271 block_header_t *header = get_header(ptr); 272 273 /* Validate the block */ 274 if (header->magic != BLOCK_MAGIC) { 275 terminal_writestring("FREE: invalid pointer (bad magic)\n"); 276 return; 277 } 278 279 if (header->is_free) { 280 terminal_writestring("FREE: double free detected\n"); 281 return; 282 } 283 284 /* Mark as free and add to free list (front insertion) */ 285 header->is_free = 1; 286 header->next_free = free_list; 287 free_list = header; 288 } 289 290 void *realloc(void *ptr, size_t size) { 291 if (!ptr) return malloc(size); 292 293 if (size == 0) { 294 free(ptr); 295 return NULL; 296 } 297 298 block_header_t *header = get_header(ptr); 299 300 /* Validate */ 301 if (header->magic != BLOCK_MAGIC) { 302 terminal_writestring("REALLOC: invalid pointer\n"); 303 return NULL; 304 } 305 306 /* If current block is large enough, reuse it */ 307 size_t aligned_size = (size + 15) & ~15; 308 if (aligned_size < MIN_BLOCK_SIZE) aligned_size = MIN_BLOCK_SIZE; 309 310 if (header->size >= aligned_size) { 311 return ptr; /* Current block is big enough */ 312 } 313 314 /* Need to allocate new block */ 315 void *new_ptr = malloc(size); 316 if (new_ptr) { 317 memcpy(new_ptr, ptr, header->size); /* Copy old data */ 318 free(ptr); 319 } 320 return new_ptr; 321 } 322 323 void *calloc(size_t nmemb, size_t size) { 324 size_t total = nmemb * size; 325 void *ptr = malloc(total); 326 /* malloc already zeros memory */ 327 return ptr; 328 } 329 330 /* ========== Program Termination ========== */ 331 332 void abort(void) { 333 while (1) { 334 __asm__ volatile ("cli; hlt"); 335 } 336 } 337 338 void exit(int status) { 339 (void)status; 340 while (1) { 341 __asm__ volatile ("cli; hlt"); 342 } 343 } 344 345 /* ========== Math Functions ========== */ 346 347 int abs(int n) { 348 return n < 0 ? -n : n; 349 } 350 351 long labs(long n) { 352 return n < 0 ? -n : n; 353 } 354 355 /* ========== String to Number Conversion ========== */ 356 357 int atoi(const char *nptr) { 358 int result = 0; 359 int sign = 1; 360 361 while (*nptr == ' ' || *nptr == '\t') nptr++; 362 363 if (*nptr == '-') { 364 sign = -1; 365 nptr++; 366 } else if (*nptr == '+') { 367 nptr++; 368 } 369 370 while (*nptr >= '0' && *nptr <= '9') { 371 result = result * 10 + (*nptr - '0'); 372 nptr++; 373 } 374 375 return sign * result; 376 } 377 378 long strtol(const char *nptr, char **endptr, int base) { 379 long result = 0; 380 int sign = 1; 381 382 while (*nptr == ' ' || *nptr == '\t') nptr++; 383 384 if (*nptr == '-') { 385 sign = -1; 386 nptr++; 387 } else if (*nptr == '+') { 388 nptr++; 389 } 390 391 if (base == 0) { 392 if (*nptr == '0') { 393 nptr++; 394 if (*nptr == 'x' || *nptr == 'X') { 395 base = 16; 396 nptr++; 397 } else { 398 base = 8; 399 } 400 } else { 401 base = 10; 402 } 403 } 404 405 while (*nptr) { 406 int digit; 407 if (*nptr >= '0' && *nptr <= '9') digit = *nptr - '0'; 408 else if (*nptr >= 'a' && *nptr <= 'z') digit = *nptr - 'a' + 10; 409 else if (*nptr >= 'A' && *nptr <= 'Z') digit = *nptr - 'A' + 10; 410 else break; 411 412 if (digit >= base) break; 413 result = result * base + digit; 414 nptr++; 415 } 416 417 if (endptr) *endptr = (char *)nptr; 418 return sign * result; 419 } 420 421 unsigned long strtoul(const char *nptr, char **endptr, int base) { 422 unsigned long result = 0; 423 424 while (*nptr == ' ' || *nptr == '\t') nptr++; 425 426 if (*nptr == '+') nptr++; 427 428 if (base == 0) { 429 if (*nptr == '0') { 430 nptr++; 431 if (*nptr == 'x' || *nptr == 'X') { 432 base = 16; 433 nptr++; 434 } else { 435 base = 8; 436 } 437 } else { 438 base = 10; 439 } 440 } 441 442 while (*nptr) { 443 int digit; 444 if (*nptr >= '0' && *nptr <= '9') digit = *nptr - '0'; 445 else if (*nptr >= 'a' && *nptr <= 'z') digit = *nptr - 'a' + 10; 446 else if (*nptr >= 'A' && *nptr <= 'Z') digit = *nptr - 'A' + 10; 447 else break; 448 449 if (digit >= base) break; 450 result = result * base + digit; 451 nptr++; 452 } 453 454 if (endptr) *endptr = (char *)nptr; 455 return result; 456 } 457 458 double strtod(const char *nptr, char **endptr) { 459 /* Very basic implementation - doesn't handle exponents */ 460 double result = 0.0; 461 double sign = 1.0; 462 463 while (*nptr == ' ' || *nptr == '\t') nptr++; 464 465 if (*nptr == '-') { 466 sign = -1.0; 467 nptr++; 468 } else if (*nptr == '+') { 469 nptr++; 470 } 471 472 while (*nptr >= '0' && *nptr <= '9') { 473 result = result * 10.0 + (*nptr - '0'); 474 nptr++; 475 } 476 477 if (*nptr == '.') { 478 double frac = 0.1; 479 nptr++; 480 while (*nptr >= '0' && *nptr <= '9') { 481 result += (*nptr - '0') * frac; 482 frac *= 0.1; 483 nptr++; 484 } 485 } 486 487 if (endptr) *endptr = (char *)nptr; 488 return sign * result; 489 } 490 491 /* ========== Random Numbers ========== */ 492 493 static unsigned int rand_seed = 1; 494 495 int rand(void) { 496 rand_seed = rand_seed * 1103515245 + 12345; 497 return (rand_seed / 65536) % 32768; 498 } 499 500 void srand(unsigned int seed) { 501 rand_seed = seed; 502 } 503 504 /* ========== Character Classification ========== */ 505 506 int isalnum(int c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } 507 int isalpha(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } 508 int isdigit(int c) { return c >= '0' && c <= '9'; } 509 int isxdigit(int c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } 510 int islower(int c) { return c >= 'a' && c <= 'z'; } 511 int isupper(int c) { return c >= 'A' && c <= 'Z'; } 512 int isspace(int c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f'; } 513 int isprint(int c) { return c >= 0x20 && c <= 0x7E; } 514 int isgraph(int c) { return c > 0x20 && c <= 0x7E; } 515 int iscntrl(int c) { return (c >= 0 && c < 0x20) || c == 0x7F; } 516 int ispunct(int c) { return isgraph(c) && !isalnum(c); } 517 518 /* ========== stdio Functions (Stubs) ========== */ 519 520 typedef struct _FILE { 521 int dummy; 522 } FILE; 523 524 FILE __stdio_files[3]; 525 FILE *stdin = &__stdio_files[0]; 526 FILE *stdout = &__stdio_files[1]; 527 FILE *stderr = &__stdio_files[2]; 528 529 /* Simple printf implementation */ 530 extern void terminal_writestring(const char *); 531 extern void terminal_putchar(char); 532 533 static void print_num(long long num, int base, int is_signed) { 534 char buf[32]; 535 int i = 0; 536 int is_negative = 0; 537 538 if (num == 0) { 539 terminal_putchar('0'); 540 return; 541 } 542 543 if (is_signed && num < 0) { 544 is_negative = 1; 545 num = -num; 546 } 547 548 while (num > 0) { 549 int digit = num % base; 550 buf[i++] = (digit < 10) ? '0' + digit : 'a' + digit - 10; 551 num /= base; 552 } 553 554 if (is_negative) terminal_putchar('-'); 555 while (i > 0) terminal_putchar(buf[--i]); 556 } 557 558 int vsnprintf(char *str, size_t size, const char *format, va_list ap) { 559 size_t pos = 0; 560 561 while (*format && pos < size - 1) { 562 if (*format == '%') { 563 format++; 564 if (*format == 'd' || *format == 'i') { 565 int val = va_arg(ap, int); 566 char buf[32]; 567 int len = 0; 568 int is_neg = val < 0; 569 if (is_neg) val = -val; 570 do { 571 buf[len++] = '0' + (val % 10); 572 val /= 10; 573 } while (val && len < 31); 574 if (is_neg && pos < size - 1) str[pos++] = '-'; 575 while (len > 0 && pos < size - 1) str[pos++] = buf[--len]; 576 } else if (*format == 'u') { 577 unsigned int val = va_arg(ap, unsigned int); 578 char buf[32]; 579 int len = 0; 580 do { 581 buf[len++] = '0' + (val % 10); 582 val /= 10; 583 } while (val && len < 31); 584 while (len > 0 && pos < size - 1) str[pos++] = buf[--len]; 585 } else if (*format == 's') { 586 const char *s = va_arg(ap, const char *); 587 while (*s && pos < size - 1) str[pos++] = *s++; 588 } else if (*format == 'c') { 589 if (pos < size - 1) str[pos++] = (char)va_arg(ap, int); 590 } else if (*format == '%') { 591 if (pos < size - 1) str[pos++] = '%'; 592 } 593 format++; 594 } else { 595 str[pos++] = *format++; 596 } 597 } 598 599 if (size > 0) str[pos] = '\0'; 600 return pos; 601 } 602 603 int vsprintf(char *str, const char *format, va_list ap) { 604 return vsnprintf(str, (size_t)-1, format, ap); 605 } 606 607 int snprintf(char *str, size_t size, const char *format, ...) { 608 va_list ap; 609 va_start(ap, format); 610 int ret = vsnprintf(str, size, format, ap); 611 va_end(ap); 612 return ret; 613 } 614 615 int sprintf(char *str, const char *format, ...) { 616 va_list ap; 617 va_start(ap, format); 618 int ret = vsprintf(str, format, ap); 619 va_end(ap); 620 return ret; 621 } 622 623 int vprintf(const char *format, va_list ap) { 624 while (*format) { 625 if (*format == '%') { 626 format++; 627 if (*format == 'd' || *format == 'i') { 628 print_num(va_arg(ap, int), 10, 1); 629 } else if (*format == 'u') { 630 print_num(va_arg(ap, unsigned int), 10, 0); 631 } else if (*format == 'x') { 632 print_num(va_arg(ap, unsigned int), 16, 0); 633 } else if (*format == 's') { 634 terminal_writestring(va_arg(ap, const char *)); 635 } else if (*format == 'c') { 636 terminal_putchar((char)va_arg(ap, int)); 637 } else if (*format == '%') { 638 terminal_putchar('%'); 639 } 640 format++; 641 } else { 642 terminal_putchar(*format++); 643 } 644 } 645 return 0; 646 } 647 648 int printf(const char *format, ...) { 649 va_list ap; 650 va_start(ap, format); 651 int ret = vprintf(format, ap); 652 va_end(ap); 653 return ret; 654 } 655 656 int fprintf(FILE *stream, const char *format, ...) { 657 (void)stream; 658 va_list ap; 659 va_start(ap, format); 660 int ret = vprintf(format, ap); 661 va_end(ap); 662 return ret; 663 } 664 665 int vfprintf(FILE *stream, const char *format, va_list ap) { 666 (void)stream; 667 return vprintf(format, ap); 668 } 669 670 int puts(const char *s) { 671 terminal_writestring(s); 672 terminal_putchar('\n'); 673 return 0; 674 } 675 676 int putchar(int c) { 677 terminal_putchar(c); 678 return c; 679 } 680 681 int fputs(const char *s, FILE *stream) { 682 (void)stream; 683 terminal_writestring(s); 684 return 0; 685 } 686 687 int fputc(int c, FILE *stream) { 688 (void)stream; 689 terminal_putchar(c); 690 return c; 691 } 692 693 FILE *fopen(const char *pathname, const char *mode) { 694 (void)pathname; (void)mode; 695 return NULL; 696 } 697 698 int fclose(FILE *stream) { 699 (void)stream; 700 return 0; 701 } 702 703 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { 704 (void)ptr; (void)size; (void)nmemb; (void)stream; 705 return 0; 706 } 707 708 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { 709 (void)ptr; (void)size; (void)nmemb; (void)stream; 710 return 0; 711 } 712 713 int fseek(FILE *stream, long offset, int whence) { 714 (void)stream; (void)offset; (void)whence; 715 return -1; 716 } 717 718 long ftell(FILE *stream) { 719 (void)stream; 720 return -1; 721 } 722 723 void rewind(FILE *stream) { 724 (void)stream; 725 } 726 727 int feof(FILE *stream) { 728 (void)stream; 729 return 0; 730 } 731 732 int ferror(FILE *stream) { 733 (void)stream; 734 return 0; 735 } 736 737 int fflush(FILE *stream) { 738 (void)stream; 739 return 0; 740 } 741 742 /* ========== Locale ========== */ 743 744 static struct lconv locale_conv = { 745 .decimal_point = ".", 746 .thousands_sep = "", 747 .grouping = "" 748 }; 749 750 char *setlocale(int category, const char *locale) { 751 (void)category; (void)locale; 752 return "C"; 753 } 754 755 struct lconv *localeconv(void) { 756 return &locale_conv; 757 } 758 759 /* ========== Time ========== */ 760 761 time_t time(time_t *t) { 762 time_t dummy = 0; 763 if (t) *t = dummy; 764 return dummy; 765 } 766 767 clock_t clock(void) { 768 return 0; 769 } 770 771 time_t mktime(struct tm *tm) { 772 (void)tm; 773 return 0; 774 } 775 776 char *getenv(const char *name) { 777 (void)name; 778 return NULL; 779 } 780 781 int system(const char *command) { 782 (void)command; 783 return -1; 784 } 785 786 struct tm *localtime_r(const time_t *timep, struct tm *result) { 787 (void)timep; 788 if (result) memset(result, 0, sizeof(struct tm)); 789 return result; 790 } 791 792 struct tm *gmtime_r(const time_t *timep, struct tm *result) { 793 (void)timep; 794 if (result) memset(result, 0, sizeof(struct tm)); 795 return result; 796 } 797 798 size_t strftime(char *s, size_t max, const char *format, const struct tm *tm) { 799 (void)format; (void)tm; 800 if (max > 0) s[0] = '\0'; 801 return 0; 802 } 803 804 int mkstemp64(char *template) { 805 (void)template; 806 errno = 38; /* ENOSYS */ 807 return -1; 808 } 809 810 int rename(const char *oldpath, const char *newpath) { 811 (void)oldpath; (void)newpath; 812 errno = 38; /* ENOSYS */ 813 return -1; 814 } 815 816 int remove(const char *pathname) { 817 (void)pathname; 818 errno = 38; /* ENOSYS */ 819 return -1; 820 } 821 822 FILE *tmpfile64(void) { 823 return NULL; 824 } 825 826 FILE *popen(const char *command, const char *type) { 827 (void)command; (void)type; 828 return NULL; 829 } 830 831 int pclose(FILE *stream) { 832 (void)stream; 833 return -1; 834 } 835 836 double difftime(time_t time1, time_t time0) { 837 return (double)(time1 - time0); 838 } 839 840 int ungetc(int c, FILE *stream) { 841 (void)c; (void)stream; 842 return EOF; 843 } 844 845 int __isoc99_fscanf(FILE *stream, const char *format, ...) { 846 (void)stream; (void)format; 847 return EOF; 848 } 849 850 int setvbuf(FILE *stream, char *buf, int mode, size_t size) { 851 (void)stream; (void)buf; (void)mode; (void)size; 852 return 0; 853 } 854 855 int fseeko64(FILE *stream, off_t offset, int whence) { 856 (void)stream; (void)offset; (void)whence; 857 return -1; 858 } 859 860 off_t ftello64(FILE *stream) { 861 (void)stream; 862 return -1; 863 } 864 865 void clearerr(FILE *stream) { 866 (void)stream; 867 } 868 869 int getc(FILE *stream) { 870 (void)stream; 871 return EOF; 872 } 873 874 /* ========== setjmp/longjmp ========== */ 875 876 int setjmp(int env[6]) { 877 __asm__ volatile ( 878 "movl %%ebx, 0(%0)\n" 879 "movl %%esi, 4(%0)\n" 880 "movl %%edi, 8(%0)\n" 881 "movl %%ebp, 12(%0)\n" 882 "leal 4(%%esp), %%eax\n" 883 "movl %%eax, 16(%0)\n" 884 "movl (%%esp), %%eax\n" 885 "movl %%eax, 20(%0)\n" 886 : : "r"(env) : "eax" 887 ); 888 return 0; 889 } 890 891 void longjmp(int env[6], int val) { 892 __asm__ volatile ( 893 "movl %1, %%eax\n" 894 "testl %%eax, %%eax\n" 895 "jnz 1f\n" 896 "incl %%eax\n" 897 "1:\n" 898 "movl 0(%0), %%ebx\n" 899 "movl 4(%0), %%esi\n" 900 "movl 8(%0), %%edi\n" 901 "movl 12(%0), %%ebp\n" 902 "movl 16(%0), %%esp\n" 903 "jmp *20(%0)\n" 904 : : "r"(env), "m"(val) : "eax" 905 ); 906 __builtin_unreachable(); 907 } 908 909 /* ========== Additional Functions for LuaJIT ========== */ 910 911 /* Additional types needed */ 912 typedef long ssize_t; 913 typedef long off_t; 914 915 void *memchr(const void *s, int c, size_t n) { 916 const unsigned char *p = s; 917 while (n--) { 918 if (*p == (unsigned char)c) return (void *)p; 919 p++; 920 } 921 return NULL; 922 } 923 924 int *__errno_location(void) { 925 return &errno; 926 } 927 928 /* Math function stubs - use GCC builtins where possible */ 929 double fabs(double x) { return __builtin_fabs(x); } 930 double floor(double x) { return __builtin_floor(x); } 931 double ceil(double x) { return __builtin_ceil(x); } 932 double sqrt(double x) { return __builtin_sqrt(x); } 933 double fmod(double x, double y) { return __builtin_fmod(x, y); } 934 double pow(double x, double y) { return __builtin_pow(x, y); } 935 double exp(double x) { return __builtin_exp(x); } 936 double log(double x) { return __builtin_log(x); } 937 double log2(double x) { return __builtin_log2(x); } 938 double log10(double x) { return __builtin_log10(x); } 939 double sin(double x) { return __builtin_sin(x); } 940 double cos(double x) { return __builtin_cos(x); } 941 double tan(double x) { return __builtin_tan(x); } 942 double asin(double x) { return __builtin_asin(x); } 943 double acos(double x) { return __builtin_acos(x); } 944 double atan(double x) { return __builtin_atan(x); } 945 double atan2(double y, double x) { return __builtin_atan2(y, x); } 946 double sinh(double x) { return __builtin_sinh(x); } 947 double cosh(double x) { return __builtin_cosh(x); } 948 double tanh(double x) { return __builtin_tanh(x); } 949 double ldexp(double x, int exp) { return __builtin_ldexp(x, exp); } 950 951 float fabsf(float x) { return __builtin_fabsf(x); } 952 float floorf(float x) { return __builtin_floorf(x); } 953 float ceilf(float x) { return __builtin_ceilf(x); } 954 float sqrtf(float x) { return __builtin_sqrtf(x); } 955 float fmodf(float x, float y) { return __builtin_fmodf(x, y); } 956 float powf(float x, float y) { return __builtin_powf(x, y); } 957 958 /* System call stubs - these will fail but won't crash */ 959 /* Linux syscall numbers */ 960 #define SYS_getrandom 318 961 962 long syscall(long number, ...) { 963 /* Debug - FIRST thing to see if we even enter */ 964 extern void terminal_writestring(const char*); 965 terminal_writestring("LIBC: syscall() ENTERED\n"); 966 967 va_list args; 968 va_start(args, number); 969 970 terminal_writestring("LIBC: checking number\n"); 971 if (number == SYS_getrandom) { 972 terminal_writestring("LIBC: number is SYS_getrandom!\n"); 973 /* getrandom(void *buf, size_t buflen, unsigned int flags) */ 974 void *buf = va_arg(args, void*); 975 size_t buflen = va_arg(args, size_t); 976 unsigned int flags = va_arg(args, unsigned int); 977 va_end(args); 978 979 /* Debug */ 980 terminal_writestring("LIBC: about to call int 0x80\n"); 981 982 /* Make system call via int 0x80 */ 983 long ret; 984 __asm__ volatile ( 985 "int $0x80" 986 : "=a"(ret) 987 : "a"(2), "b"(buf), "c"(buflen), "d"(flags) /* syscall 2 = SYSCALL_GETRANDOM */ 988 ); 989 990 /* Debug return value */ 991 terminal_writestring("LIBC: syscall returned "); 992 char num[16]; 993 int i = 0; 994 long n = ret; 995 if (n < 0) { 996 terminal_writestring("-"); 997 n = -n; 998 } 999 do { num[i++] = '0' + (n % 10); n /= 10; } while (n > 0); 1000 while (i > 0) { 1001 char c = num[--i]; 1002 extern void terminal_putchar(char); 1003 terminal_putchar(c); 1004 } 1005 terminal_putchar('\n'); 1006 1007 return ret; 1008 } 1009 1010 va_end(args); 1011 errno = 38; /* ENOSYS */ 1012 return -1; 1013 } 1014 1015 int open64(const char *pathname, int flags, ...) { 1016 (void)pathname; (void)flags; 1017 errno = 38; /* ENOSYS */ 1018 return -1; 1019 } 1020 1021 ssize_t read(int fd, void *buf, size_t count) { 1022 (void)fd; (void)buf; (void)count; 1023 errno = 38; /* ENOSYS */ 1024 return -1; 1025 } 1026 1027 int close(int fd) { 1028 (void)fd; 1029 return 0; 1030 } 1031 1032 /* mmap - memory map stub (uses our allocator with block headers) */ 1033 /* All memory is executable in bare metal x86, so PROT_EXEC works automatically */ 1034 void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { 1035 (void)addr; (void)fd; (void)offset; 1036 1037 terminal_writestring("MMAP: len="); 1038 print_hex(length); 1039 terminal_writestring(" prot="); 1040 print_hex(prot); 1041 terminal_writestring(" flags="); 1042 print_hex(flags); 1043 terminal_writestring("\n"); 1044 1045 /* Allocate from our heap - LuaJIT uses this heavily */ 1046 if (length == 0) { 1047 errno = 22; /* EINVAL */ 1048 terminal_writestring("MMAP: length=0, FAIL\n"); 1049 return (void *)-1; 1050 } 1051 1052 /* Align to page boundary (4KB) */ 1053 size_t aligned_length = (length + 4095) & ~4095; 1054 1055 /* Use malloc which now supports free */ 1056 void *ptr = malloc(aligned_length); 1057 if (!ptr) { 1058 terminal_writestring("MMAP OOM: need="); 1059 print_hex(aligned_length); 1060 terminal_writestring(" heap_end="); 1061 print_hex(heap_end); 1062 terminal_writestring("\n"); 1063 errno = 12; /* ENOMEM */ 1064 return (void *)-1; 1065 } 1066 1067 terminal_writestring("MMAP OK: ptr="); 1068 print_hex((unsigned long)ptr); 1069 terminal_writestring(" used="); 1070 print_hex(heap_end); 1071 terminal_writestring("/"); 1072 print_hex(HEAP_SIZE); 1073 terminal_writestring("\n"); 1074 1075 return ptr; 1076 } 1077 1078 void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { 1079 /* Just call regular mmap */ 1080 return mmap(addr, length, prot, flags, fd, offset); 1081 } 1082 1083 int munmap(void *addr, size_t length) { 1084 (void)length; 1085 /* Actually free the memory now */ 1086 if (addr) { 1087 free(addr); 1088 } 1089 return 0; 1090 } 1091 1092 int mprotect(void *addr, size_t len, int prot) { 1093 (void)addr; (void)len; (void)prot; 1094 return 0; 1095 } 1096 1097 /* Dynamic loading stubs */ 1098 void *dlopen(const char *filename, int flags) { 1099 (void)filename; (void)flags; 1100 return NULL; 1101 } 1102 1103 void *dlsym(void *handle, const char *symbol) { 1104 (void)handle; (void)symbol; 1105 return NULL; 1106 } 1107 1108 int dlclose(void *handle) { 1109 (void)handle; 1110 return 0; 1111 } 1112 1113 char *dlerror(void) { 1114 return "Dynamic loading not supported"; 1115 } 1116 1117 FILE *fopen64(const char *pathname, const char *mode) { 1118 (void)pathname; (void)mode; 1119 return NULL; 1120 } 1121 1122 char *fgets(char *s, int size, FILE *stream) { 1123 (void)s; (void)size; (void)stream; 1124 return NULL; 1125 } 1126 1127 /* Unwind stubs for exception handling */ 1128 typedef void *_Unwind_Exception_Ptr; 1129 typedef void *_Unwind_Context_Ptr; 1130 typedef int _Unwind_Reason_Code; 1131 1132 void _Unwind_SetGR(_Unwind_Context_Ptr ctx, int index, unsigned long val) { 1133 (void)ctx; (void)index; (void)val; 1134 } 1135 1136 void _Unwind_SetIP(_Unwind_Context_Ptr ctx, unsigned long val) { 1137 (void)ctx; (void)val; 1138 } 1139 1140 void _Unwind_DeleteException(_Unwind_Exception_Ptr exc) { 1141 (void)exc; 1142 } 1143 1144 void __deregister_frame(void *fde) { 1145 (void)fde; 1146 } 1147 1148 void __register_frame(void *fde) { 1149 (void)fde; 1150 } 1151 1152 _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception_Ptr exc) { 1153 (void)exc; 1154 return 5; /* _URC_END_OF_STACK */ 1155 } 1156 1157 unsigned long _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr ctx) { 1158 (void)ctx; 1159 return 0; 1160 } 1161 1162 unsigned long _Unwind_GetIP(_Unwind_Context_Ptr ctx) { 1163 (void)ctx; 1164 return 0; 1165 } 1166 1167 unsigned long _Unwind_GetRegionStart(_Unwind_Context_Ptr ctx) { 1168 (void)ctx; 1169 return 0; 1170 } 1171 1172 unsigned long _Unwind_GetCFA(_Unwind_Context_Ptr ctx) { 1173 (void)ctx; 1174 return 0; 1175 } 1176 1177 /* Signal handling stubs */ 1178 typedef void (*sighandler_t)(int); 1179 1180 struct itimerval { 1181 struct timeval { 1182 long tv_sec; 1183 long tv_usec; 1184 } it_interval, it_value; 1185 }; 1186 1187 struct sigaction { 1188 sighandler_t sa_handler; 1189 unsigned long sa_flags; 1190 void (*sa_restorer)(void); 1191 unsigned long sa_mask[16]; 1192 }; 1193 1194 int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) { 1195 (void)which; (void)new_value; (void)old_value; 1196 return -1; 1197 } 1198 1199 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) { 1200 (void)signum; (void)act; (void)oldact; 1201 return 0; 1202 } 1203 1204 int sigemptyset(unsigned long *set) { 1205 *set = 0; 1206 return 0; 1207 } 1208 1209 /* String functions */ 1210 char *strerror(int errnum) { 1211 (void)errnum; 1212 return "Error"; 1213 } 1214 1215 int putc(int c, FILE *stream) { 1216 (void)stream; 1217 terminal_putchar(c); 1218 return c; 1219 } 1220 1221 /* More math functions */ 1222 double frexp(double x, int *exp) { 1223 (void)x; (void)exp; 1224 *exp = 0; 1225 return x; 1226 } 1227 1228 double modf(double x, double *iptr) { 1229 double int_part = (double)(long)x; 1230 *iptr = int_part; 1231 return x - int_part; 1232 } 1233 1234 /* Memory remapping - allocate new and copy, free old */ 1235 void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, ...) { 1236 (void)flags; 1237 1238 if (new_size == 0) { 1239 errno = 22; /* EINVAL */ 1240 return (void *)-1; 1241 } 1242 1243 /* Align to page boundary */ 1244 new_size = (new_size + 4095) & ~4095; 1245 1246 /* Allocate new memory using our allocator */ 1247 void *new_ptr = malloc(new_size); 1248 if (!new_ptr) { 1249 errno = 12; /* ENOMEM */ 1250 return (void *)-1; 1251 } 1252 1253 /* Copy old data */ 1254 if (old_address && old_size > 0) { 1255 size_t copy_size = old_size < new_size ? old_size : new_size; 1256 memcpy(new_ptr, old_address, copy_size); 1257 /* Free the old memory */ 1258 free(old_address); 1259 } 1260 1261 return new_ptr; 1262 }