0ee872e612de57a909d7666fb44d4749d0a46044
[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 int
178 putchar (int c)
179 {
180   write (STDOUT, (char*)&c, 1);
181   return 0;
182 }
183
184 char *g_brk = 0;
185
186 void *
187 malloc (size_t size)
188 {
189   if (!g_brk)
190     g_brk = brk (0);
191   if (brk (g_brk + size) == -1)
192     return 0;
193   char *p = g_brk;
194   g_brk += size;
195   return p;
196 }
197
198 #if !FULL_MALLOC
199 void *
200 realloc (void *p, size_t size)
201 {
202   brk (g_brk + size);
203   return g_brk;
204 }
205 #endif
206
207 size_t
208 strlen (char const* s)
209 {
210   int i = 0;
211   while (s[i]) i++;
212   return i;
213 }
214
215 int
216 strcmp (char const* a, char const* b)
217 {
218   while (*a && *b && *a == *b) {a++;b++;}
219   return *a - *b;
220 }
221
222 char *
223 strcpy (char *dest, char const *src)
224 {
225   char *p = dest;
226   while (*src) *p++ = *src++;
227   *p = 0;
228   return dest;
229 }
230
231 int
232 eputs (char const* s)
233 {
234   int i = strlen (s);
235   write (STDERR, s, i);
236   return 0;
237 }
238
239 int
240 fputs (char const* s, int fd)
241 {
242   int i = strlen (s);
243   write (fd, s, i);
244   return 0;
245 }
246
247 int
248 puts (char const* s)
249 {
250   int i = strlen (s);
251   write (STDOUT, s, i);
252   return 0;
253 }
254
255 void
256 assert_fail (char* s)
257 {
258   eputs ("assert fail: ");
259   eputs (s);
260   eputs ("\n");
261   *((int*)0) = 0;
262 }
263
264 #define assert(x) ((x) ? (void)0 : assert_fail (#x))
265
266 int ungetc_char = -1;
267 char ungetc_buf[2];
268
269 int
270 getchar ()
271 {
272   char c;
273   int i;
274   if (ungetc_char == -1)
275     {
276       int r = read (g_stdin, &c, 1);
277       if (r < 1) return -1;
278       i = c;
279     }
280   else
281     i = ungetc_buf[ungetc_char--];
282
283   if (i < 0) i += 256;
284
285   return i;
286 }
287
288 int
289 ungetc (int c, int fd)
290 {
291   assert (ungetc_char < 2);
292   ungetc_buf[++ungetc_char] = c;
293   return c;
294 }
295
296 char const* itoa (int);
297
298 int
299 strncmp (char const* a, char const* b, size_t length)
300 {
301   while (*a && *b && *a == *b && --length) {a++;b++;}
302   return *a - *b;
303 }
304
305 char *
306 getenv (char const* s)
307 {
308   char **p = g_environment;
309   int length = strlen (s);
310   while (*p)
311     {
312       if (!strncmp (s, *p, length) && *(*p + length) == '=') return (*p + length + 1);
313       p++;
314     }
315   return 0;
316 }
317
318 int
319 isdigit (int c)
320 {
321   return (c>='0') && (c<='9');
322 }
323
324 int
325 atoi (char const *s)
326 {
327   int i = 0;
328   int sign = 1;
329   if (*s && *s == '-')
330     {
331       sign = -1;
332       s++;
333     }
334   while (isdigit (*s))
335     {
336       i *= 10;
337       i += (*s - '0');
338       s++;
339     }
340   return i * sign;
341 }
342
343
344 // FIXME: copied from libc-mes.c now
345 #include <stdarg.h>
346
347 int
348 vprintf (char const* format, va_list ap)
349 {
350   char const *p = format;
351   while (*p)
352     if (*p != '%')
353       putchar (*p++);
354     else
355       {
356         p++;
357         char c = *p;
358         switch (c)
359           {
360           case '%': {putchar (*p); break;}
361           case 'c': {char c; c = va_arg (ap, char); putchar (c); break;}
362           case 'd': {int d; d = va_arg (ap, int); puts (itoa (d)); break;}
363           case 's': {char *s; s = va_arg (ap, char *); puts (s); break;}
364           default: putchar (*p);
365           }
366         p++;
367       }
368   va_end (ap);
369   return 0;
370 }
371
372 int
373 printf (char const* format, ...)
374 {
375   va_list ap;
376   va_start (ap, format);
377   int r = vprintf (format, ap);
378   va_end (ap);
379   return r;
380 }
381
382 int
383 sprintf (char *str, char const* format, ...)
384 {
385   va_list ap;
386   va_start (ap, format);
387   char const *p = format;
388   while (*p)
389     if (*p != '%')
390       *str++ = *p++;
391     else
392       {
393         p++;
394         char c = *p;
395         switch (c)
396           {
397           case '%': {*str++ = *p; break;}
398           case 'c': {char c; c = va_arg (ap, char); *str++ = c; break;}
399           case 'd': {int d; d = va_arg (ap, int); char const *s = itoa (d); while (*s) *str++ = *s++; break;}
400           case 's': {char *s; s = va_arg (ap, char *); while (*s) *str++ = *s++; break;}
401           default: *str++ = *p;
402           }
403         p++;
404       }
405   va_end (ap);
406   return 0;
407 }
408 #endif
409
410 char itoa_buf[10];
411
412 char const*
413 itoa (int x)
414 {
415   //static char itoa_buf[10];
416   //char *p = buf+9;
417   char *p = itoa_buf;
418   p += 9;
419   *p-- = 0;
420
421   //int sign = x < 0;
422   int sign;
423   sign = x < 0;
424   if (sign)
425     x = -x;
426
427   do
428     {
429       *p-- = '0' + (x % 10);
430       x = x / 10;
431     } while (x);
432
433   if (sign)
434     *p-- = '-';
435
436   return p+1;
437 }
438
439 #if POSIX
440 #define _GNU_SOURCE
441 #include <assert.h>
442 #include <fcntl.h>
443 #include <string.h>
444 #include <unistd.h>
445 #endif // POSIX
446
447 int
448 fdputs (char const* s, int fd)
449 {
450   int i = strlen (s);
451   write (fd, s, i);
452   return 0;
453 }
454
455 #if POSIX
456
457 int
458 fdputc (int c, int fd)
459 {
460   write (fd, (char*)&c, 1);
461   return 0;
462 }
463
464 int
465 putchar (int c)
466 {
467   write (STDOUT, (char*)&c, 1);
468   return 0;
469 }
470
471 int ungetc_char = -1;
472 char ungetc_buf[2];
473
474 int
475 getchar ()
476 {
477   char c;
478   int i;
479   if (ungetc_char == -1)
480     {
481       int r = read (g_stdin, &c, 1);
482       if (r < 1) return -1;
483       i = c;
484     }
485   else
486     i = ungetc_buf[ungetc_char--];
487
488   if (i < 0) i += 256;
489
490   return i;
491 }
492
493 int
494 fdungetc (int c, int fd)
495 {
496   assert (ungetc_char < 2);
497   ungetc_buf[++ungetc_char] = c;
498   return c;
499 }
500
501 #endif // POSIX
502
503 #if __GNUC__ && !POSIX
504
505 void
506 _start ()
507 {
508   //  char **;
509   asm (
510        "mov     %%ebp,%%eax\n\t"
511        "addl    $4,%%eax\n\t"
512        "movzbl  (%%eax),%%eax\n\t"
513        "addl    $3,%%eax\n\t"
514        "shl     $2,%%eax\n\t"
515        "add     %%ebp,%%eax\n\t"
516        "movl    %%eax,%0\n\t"
517        : "=g_environment" (g_environment)
518        : //no inputs ""
519        );
520   int r;
521   asm (
522        "mov     %%ebp,%%eax\n\t"
523        "addl    $8,%%eax\n\t"
524        "push    %%eax\n\t"
525
526        "mov     %%ebp,%%eax\n\t"
527        "addl    $4,%%eax\n\t"
528        "movzbl  (%%eax),%%eax\n\t"
529        "push     %%eax\n\t"
530
531        "call    main\n\t"
532        "movl    %%eax,%0\n\t"
533        : "=r" (r)
534        : //no inputs ""
535        );
536   exit (r);
537 }
538
539 #endif // __GNUC__ && !POSIX