d278e00b212deba6278608215859826358b80285
[mes.git] / mlibc / libc-gcc.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
4  *
5  * This file is part of Mes.
6  *
7  * Mes is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * Mes is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Mes.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 char **g_environment = 0;
22 int g_stdin = 0;
23
24 #include <stdio.h>
25 #include <mlibc.h>
26
27 #if __GNUC__
28 #include <stdlib.h>
29 #endif
30
31 #if __GNUC__ && !POSIX
32
33 void
34 exit (int code)
35 {
36   asm (
37        "mov    %0,%%ebx\n\t"
38        "mov    $1,%%eax\n\t"
39        "int    $0x80"
40        : // no outputs "=" (r)
41        : "" (code)
42        );
43   // not reached
44   exit (0);
45 }
46
47 int
48 read (int fd, void* buf, size_t n)
49 {
50   int r;
51   //syscall (SYS_write, fd, s, n));
52   asm (
53        "mov    %1,%%ebx\n\t"
54        "mov    %2,%%ecx\n\t"
55        "mov    %3,%%edx\n\t"
56
57        "movl $0x3,%%eax\n\t"
58        "int  $0x80\n\t"
59
60        "mov    %%eax,%0\n\t"
61        : "=r" (r)
62        : "" (fd), "" (buf), "" (n)
63        : "eax", "ebx", "ecx", "edx"
64        );
65   return r;
66 }
67
68 int
69 write (int fd, char const* s, int n)
70 {
71   int r;
72   //syscall (SYS_write, fd, s, n));
73   asm (
74        "mov    %1,%%ebx\n\t"
75        "mov    %2,%%ecx\n\t"
76        "mov    %3,%%edx\n\t"
77
78        "mov    $0x4, %%eax\n\t"
79        "int    $0x80\n\t"
80        "mov    %%eax,%0\n\t"
81        : "=r" (r)
82        : "" (fd), "" (s), "" (n)
83        : "eax", "ebx", "ecx", "edx"
84        );
85   return r;
86 }
87
88 int
89 open (char const *s, int flags, ...)
90 {
91   int mode;
92   asm (
93        "mov    %%ebp,%%eax\n\t"
94        "add    $0x10,%%eax\n\t"
95        "mov    (%%eax),%%eax\n\t"
96        "mov    %%eax,%0\n\t"
97        : "=mode" (mode)
98        : //no inputs ""
99        );
100   int r;
101   //syscall (SYS_open, mode));
102   asm (
103        "mov    %1,%%ebx\n\t"
104        "mov    %2,%%ecx\n\t"
105        "mov    %3,%%edx\n\t"
106        "mov    $0x5,%%eax\n\t"
107        "int    $0x80\n\t"
108        "mov    %%eax,%0\n\t"
109        : "=r" (r)
110        : "" (s), "" (flags), "" (mode)
111        : "eax", "ebx", "ecx", "edx"
112        );
113   return r;
114 }
115
116 int
117 access (char const *s, int mode)
118 {
119   int r;
120   //syscall (SYS_access, mode));
121   asm (
122        "mov    %1,%%ebx\n\t"
123        "mov    %2,%%ecx\n\t"
124        "mov    $0x21,%%eax\n\t"
125        "int    $0x80\n\t"
126        "mov    %%eax,%0\n\t"
127        : "=r" (r)
128        : "" (s), "" (mode)
129        : "eax", "ebx", "ecx"
130        );
131   return r;
132 }
133
134 void *
135 brk (void *p)
136 {
137   void *r;
138   asm (
139        "mov    %1,%%ebx\n\t"
140
141        "mov    $0x2d,%%eax\n\t"
142        "int    $0x80\n\t"
143
144        "mov    %%eax,%0\n\t"
145        : "=r" (r)
146        : "" (p)
147        : "eax", "ebx"
148        );
149   return r;
150 }
151
152 int
153 fsync (int fd)
154 {
155   int r;
156   //syscall (SYS_fsync, fd));
157   asm (
158        "mov    %1,%%ebx\n\t"
159
160        "mov    $0x76, %%eax\n\t"
161        "int    $0x80\n\t"
162        "mov    %%eax,%0\n\t"
163        : "=r" (r)
164        : "" (fd)
165        : "eax", "ebx"
166        );
167   return r;
168 }
169
170 int
171 fputc (int c, int fd)
172 {
173   write (fd, (char*)&c, 1);
174   return 0;
175 }
176
177 void
178 free (void *ptr)
179 {
180 }
181
182 char *g_brk = 0;
183
184 void *
185 malloc (size_t size)
186 {
187   if (!g_brk)
188     g_brk = brk (0);
189   if ((int)brk (g_brk + size) == -1)
190     return 0;
191   char *p = g_brk;
192   g_brk += size;
193   return p;
194 }
195
196 void *
197 memcpy (void *dest, void const *src, size_t n)
198 {
199   char* p = dest;
200   char const* q = src;
201   while (n--) *p++ = *q++;
202   return dest;
203 }
204
205 int
206 putchar (int c)
207 {
208   write (STDOUT, (char*)&c, 1);
209   return 0;
210 }
211
212 void *
213 realloc (void *ptr, size_t size)
214 {
215   void *new = malloc (size);
216   if (ptr && new)
217     {
218       memcpy (new, ptr, size);
219       free (ptr);
220     }
221   return new;
222 }
223
224 size_t
225 strlen (char const* s)
226 {
227   int i = 0;
228   while (s[i]) i++;
229   return i;
230 }
231
232 int
233 strcmp (char const* a, char const* b)
234 {
235   while (*a && *b && *a == *b) {a++;b++;}
236   return *a - *b;
237 }
238
239 char *
240 strcpy (char *dest, char const *src)
241 {
242   char *p = dest;
243   while (*src) *p++ = *src++;
244   *p = 0;
245   return dest;
246 }
247
248 int
249 fputs (char const* s, int fd)
250 {
251   int i = strlen (s);
252   write (fd, s, i);
253   return 0;
254 }
255
256 int
257 puts (char const* s)
258 {
259   int i = strlen (s);
260   write (STDOUT, s, i);
261   return 0;
262 }
263
264 void
265 assert_fail (char* s)
266 {
267   eputs ("assert fail: ");
268   eputs (s);
269   eputs ("\n");
270   *((int*)0) = 0;
271 }
272
273 #define assert(x) ((x) ? (void)0 : assert_fail (#x))
274
275 int ungetc_char = -1;
276 char ungetc_buf[2];
277
278 int
279 getchar ()
280 {
281   char c;
282   int i;
283   if (ungetc_char == -1)
284     {
285       int r = read (g_stdin, &c, 1);
286       if (r < 1) return -1;
287       i = c;
288     }
289   else
290     i = ungetc_buf[ungetc_char--];
291
292   if (i < 0) i += 256;
293
294   return i;
295 }
296
297 int
298 ungetc (int c, int fd)
299 {
300   assert (ungetc_char < 2);
301   ungetc_buf[++ungetc_char] = c;
302   return c;
303 }
304
305 char const* itoa (int);
306
307 int
308 strncmp (char const* a, char const* b, size_t length)
309 {
310   while (*a && *b && *a == *b && --length) {a++;b++;}
311   return *a - *b;
312 }
313
314 char *
315 getenv (char const* s)
316 {
317   char **p = g_environment;
318   int length = strlen (s);
319   while (*p)
320     {
321       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
322       p++;
323     }
324   return 0;
325 }
326
327 int
328 isdigit (int c)
329 {
330   return (c>='0') && (c<='9');
331 }
332
333 int
334 isxdigit (int c)
335 {
336   return isdigit (c) || (c>='a') && (c<='f');
337 }
338
339 int
340 isnumber (int c, int base)
341 {
342   if (base == 2)
343     return (c>='0') && (c<='1');
344   if (base == 8)
345     return (c>='0') && (c<='7');
346   if (base == 10)
347     return isdigit (c);
348   if (base == 16)
349     return isxdigit (c);
350 }
351
352 int
353 _atoi (char const **p, int base)
354 {
355   char const *s = *p;
356   int i = 0;
357   int sign = 1;
358   if (!base) base = 10;
359   if (*s && *s == '-')
360     {
361       sign = -1;
362       s++;
363     }
364   while (isnumber (*s, base))
365     {
366       i *= base;
367       int m = *s > '9' ? 'a' - 10 : '0';
368       i += *s - m;
369       s++;
370     }
371   *p = s;
372   return i * sign;
373 }
374
375 int
376 atoi (char const *s)
377 {
378   char const *p = s;
379   return _atoi (&p, 0);
380 }
381
382 // FIXME: copied from libc-mes.c now
383 #include <stdarg.h>
384
385 int
386 vprintf (char const* format, va_list ap)
387 {
388   char const *p = format;
389   while (*p)
390     if (*p != '%')
391       putchar (*p++);
392     else
393       {
394         p++;
395         char c = *p;
396         switch (c)
397           {
398           case '%': {putchar (*p); break;}
399           case 'c': {char c; c = va_arg (ap, char); putchar (c); break;}
400           case 'd': {int d; d = va_arg (ap, int); puts (itoa (d)); break;}
401           case 's': {char *s; s = va_arg (ap, char *); puts (s); break;}
402           default: putchar (*p);
403           }
404         p++;
405       }
406   va_end (ap);
407   return 0;
408 }
409
410 int
411 printf (char const* format, ...)
412 {
413   va_list ap;
414   va_start (ap, format);
415   int r = vprintf (format, ap);
416   va_end (ap);
417   return r;
418 }
419
420 int
421 vsprintf (char *str, char const* format, va_list ap)
422 {
423   char const *p = format;
424   while (*p)
425     if (*p != '%')
426       *str++ = *p++;
427     else
428       {
429         p++;
430         char c = *p;
431         switch (c)
432           {
433           case '%': {*str++ = *p; break;}
434           case 'c': {char c; c = va_arg (ap, char); *str++ = c; break;}
435           case 'd': {int d; d = va_arg (ap, int); char const *s = itoa (d); while (*s) *str++ = *s++; break;}
436           case 's': {char *s; s = va_arg (ap, char *); while (*s) *str++ = *s++; break;}
437           default: *str++ = *p;
438           }
439         p++;
440       }
441
442   *str = 0;
443   return strlen (str);
444 }
445
446 int
447 sprintf (char *str, char const* format, ...)
448 {
449   va_list ap;
450   va_start (ap, format);
451   int r = vsprintf (str, format, ap);
452   va_end (ap);
453   return r;
454 }
455 #endif
456
457 char itoa_buf[10];
458
459 char const*
460 itoa (int x)
461 {
462   //static char itoa_buf[10];
463   //char *p = buf+9;
464   char *p = itoa_buf;
465   p += 9;
466   *p-- = 0;
467
468   //int sign = x < 0;
469   int sign;
470   sign = x < 0;
471   if (sign)
472     x = -x;
473
474   do
475     {
476       *p-- = '0' + (x % 10);
477       x = x / 10;
478     } while (x);
479
480   if (sign)
481     *p-- = '-';
482
483   return p+1;
484 }
485
486 #if POSIX
487 #define _GNU_SOURCE
488 #include <assert.h>
489 #include <fcntl.h>
490 #include <string.h>
491 #include <unistd.h>
492 #endif // POSIX
493
494 int
495 fdputs (char const* s, int fd)
496 {
497   int i = strlen (s);
498   write (fd, s, i);
499   return 0;
500 }
501
502 int
503 eputc (int c)
504 {
505   return fdputc (c, STDERR);
506 }
507
508 int
509 eputs (char const* s)
510 {
511   return fdputs (s, STDERR);
512 }
513
514 int
515 fdputc (int c, int fd)
516 {
517   write (fd, (char*)&c, 1);
518   return 0;
519 }
520
521 #if POSIX
522
523 int
524 putchar (int c)
525 {
526   write (STDOUT, (char*)&c, 1);
527   return 0;
528 }
529
530 int ungetc_char = -1;
531 char ungetc_buf[2];
532
533 int
534 getchar ()
535 {
536   char c;
537   int i;
538   if (ungetc_char == -1)
539     {
540       int r = read (g_stdin, &c, 1);
541       if (r < 1) return -1;
542       i = c;
543     }
544   else
545     i = ungetc_buf[ungetc_char--];
546
547   if (i < 0) i += 256;
548
549   return i;
550 }
551
552 int
553 fdungetc (int c, int fd)
554 {
555   assert (ungetc_char < 2);
556   ungetc_buf[++ungetc_char] = c;
557   return c;
558 }
559
560 #endif // POSIX
561
562 #if __GNUC__ && !POSIX
563
564 void
565 _start ()
566 {
567   //  char **;
568   asm (
569        "mov     %%ebp,%%eax\n\t"
570        "addl    $4,%%eax\n\t"
571        "movzbl  (%%eax),%%eax\n\t"
572        "addl    $3,%%eax\n\t"
573        "shl     $2,%%eax\n\t"
574        "add     %%ebp,%%eax\n\t"
575        "movl    %%eax,%0\n\t"
576        : "=g_environment" (g_environment)
577        : //no inputs ""
578        );
579   int r;
580   asm (
581        "mov     %%ebp,%%eax\n\t"
582        "addl    $8,%%eax\n\t"
583        "push    %%eax\n\t"
584
585        "mov     %%ebp,%%eax\n\t"
586        "addl    $4,%%eax\n\t"
587        "movzbl  (%%eax),%%eax\n\t"
588        "push     %%eax\n\t"
589
590        "call    main\n\t"
591        "movl    %%eax,%0\n\t"
592        : "=r" (r)
593        : //no inputs ""
594        );
595   exit (r);
596 }
597
598 #endif // __GNUC__ && !POSIX