History

new subdirs: include, lib, tests

grischka committed 17 years ago

Commit ea5e81b1 parent e8a52a816 files · +0 −6Browse files

Showing the changes to lib (4 of 16 files). Show all

Unified · Split

4 files
  1. lib/alloca86-bt.S +45 −0
  2. lib/alloca86.S +33 −0
  3. lib/bcheck.c +868 −0
  4. lib/libtcc1.c +607 −0
lib/alloca86-bt.S+45−0
@@ -0,0 +1,45 @@
1/* ---------------------------------------------- */
2/* alloca86b.S */
3
4#include "config.h"
5
6.globl __bound__alloca
7
8__bound__alloca:
9 pop %edx
10 pop %eax
11 mov %eax, %ecx
12 add $3,%eax
13 and $-4,%eax
14 jz p6
15
16#ifdef TCC_TARGET_PE
17p4:
18 cmp $4096,%eax
19 jle p5
20 sub $4096,%esp
21 sub $4096,%eax
22 test %eax,(%esp)
23 jmp p4
24
25p5:
26#endif
27
28 sub %eax,%esp
29 mov %esp,%eax
30
31 push %edx
32 push %eax
33 push %ecx
34 push %eax
35 call __bound_new_region
36 add $8, %esp
37 pop %eax
38 pop %edx
39
40p6:
41 push %edx
42 push %edx
43 ret
44
45/* ---------------------------------------------- */
lib/alloca86.S+33−0
@@ -0,0 +1,33 @@
1/* ---------------------------------------------- */
2/* alloca86.S */
3
4#include "config.h"
5
6.globl _alloca
7
8_alloca:
9 pop %edx
10 pop %eax
11 add $3,%eax
12 and $-4,%eax
13 jz p3
14
15#ifdef TCC_TARGET_PE
16p1:
17 cmp $4096,%eax
18 jle p2
19 sub $4096,%esp
20 sub $4096,%eax
21 test %eax,(%esp)
22 jmp p1
23p2:
24#endif
25
26 sub %eax,%esp
27 mov %esp,%eax
28p3:
29 push %edx
30 push %edx
31 ret
32
33/* ---------------------------------------------- */
lib/bcheck.c+868−0
@@ -0,0 +1,868 @@
1/*
2 * Tiny C Memory and bounds checker
3 *
4 * Copyright (c) 2002 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <stdlib.h>
21#include <stdio.h>
22#include <stdarg.h>
23#include <string.h>
24#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
25#include <malloc.h>
26#endif
27
28//#define BOUND_DEBUG
29
30/* define so that bound array is static (faster, but use memory if
31 bound checking not used) */
32//#define BOUND_STATIC
33
34/* use malloc hooks. Currently the code cannot be reliable if no hooks */
35#define CONFIG_TCC_MALLOC_HOOKS
36
37#define HAVE_MEMALIGN
38
39#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
40 || defined(__UCLIBC__) || defined(__OpenBSD__)
41#warning Bound checking not fully supported in this environment.
42#undef CONFIG_TCC_MALLOC_HOOKS
43#undef HAVE_MEMALIGN
44#endif
45
46#define BOUND_T1_BITS 13
47#define BOUND_T2_BITS 11
48#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
49
50#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
51#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
52#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
53#define BOUND_E_BITS 4
54
55#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
56#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
57
58
59/* this pointer is generated when bound check is incorrect */
60#define INVALID_POINTER ((void *)(-2))
61/* size of an empty region */
62#define EMPTY_SIZE 0xffffffff
63/* size of an invalid region */
64#define INVALID_SIZE 0
65
66typedef struct BoundEntry {
67 unsigned long start;
68 unsigned long size;
69 struct BoundEntry *next;
70 unsigned long is_invalid; /* true if pointers outside region are invalid */
71} BoundEntry;
72
73/* external interface */
74void __bound_init(void);
75void __bound_new_region(void *p, unsigned long size);
76int __bound_delete_region(void *p);
77
78#define FASTCALL __attribute__((regparm(3)))
79
80void *__bound_malloc(size_t size, const void *caller);
81void *__bound_memalign(size_t size, size_t align, const void *caller);
82void __bound_free(void *ptr, const void *caller);
83void *__bound_realloc(void *ptr, size_t size, const void *caller);
84static void *libc_malloc(size_t size);
85static void libc_free(void *ptr);
86static void install_malloc_hooks(void);
87static void restore_malloc_hooks(void);
88
89#ifdef CONFIG_TCC_MALLOC_HOOKS
90static void *saved_malloc_hook;
91static void *saved_free_hook;
92static void *saved_realloc_hook;
93static void *saved_memalign_hook;
94#endif
95
96/* linker definitions */
97extern char _end;
98
99/* TCC definitions */
100extern char __bounds_start; /* start of static bounds table */
101/* error message, just for TCC */
102const char *__bound_error_msg;
103
104/* runtime error output */
105extern void rt_error(unsigned long pc, const char *fmt, ...);
106
107#ifdef BOUND_STATIC
108static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
109#else
110static BoundEntry **__bound_t1; /* page table */
111#endif
112static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
113static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
114
115static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
116{
117 unsigned long addr, tmp;
118 BoundEntry *e;
119
120 e = e1;
121 while (e != NULL) {
122 addr = (unsigned long)p;
123 addr -= e->start;
124 if (addr <= e->size) {
125 /* put region at the head */
126 tmp = e1->start;
127 e1->start = e->start;
128 e->start = tmp;
129 tmp = e1->size;
130 e1->size = e->size;
131 e->size = tmp;
132 return e1;
133 }
134 e = e->next;
135 }
136 /* no entry found: return empty entry or invalid entry */
137 if (e1->is_invalid)
138 return __bound_invalid_t2;
139 else
140 return __bound_empty_t2;
141}
142
143/* print a bound error message */
144static void bound_error(const char *fmt, ...)
145{
146 __bound_error_msg = fmt;
147 *(int *)0 = 0; /* force a runtime error */
148}
149
150static void bound_alloc_error(void)
151{
152 bound_error("not enough memory for bound checking code");
153}
154
155/* currently, tcc cannot compile that because we use GNUC extensions */
156#if !defined(__TINYC__)
157
158/* return '(p + offset)' for pointer arithmetic (a pointer can reach
159 the end of a region in this case */
160void * FASTCALL __bound_ptr_add(void *p, int offset)
161{
162 unsigned long addr = (unsigned long)p;
163 BoundEntry *e;
164#if defined(BOUND_DEBUG)
165 printf("add: 0x%x %d\n", (int)p, offset);
166#endif
167
168 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
169 e = (BoundEntry *)((char *)e +
170 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
171 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
172 addr -= e->start;
173 if (addr > e->size) {
174 e = __bound_find_region(e, p);
175 addr = (unsigned long)p - e->start;
176 }
177 addr += offset;
178 if (addr > e->size)
179 return INVALID_POINTER; /* return an invalid pointer */
180 return p + offset;
181}
182
183/* return '(p + offset)' for pointer indirection (the resulting must
184 be strictly inside the region */
185#define BOUND_PTR_INDIR(dsize) \
186void * FASTCALL __bound_ptr_indir ## dsize (void *p, int offset) \
187{ \
188 unsigned long addr = (unsigned long)p; \
189 BoundEntry *e; \
190 \
191 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
192 e = (BoundEntry *)((char *)e + \
193 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
194 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
195 addr -= e->start; \
196 if (addr > e->size) { \
197 e = __bound_find_region(e, p); \
198 addr = (unsigned long)p - e->start; \
199 } \
200 addr += offset + dsize; \
201 if (addr > e->size) \
202 return INVALID_POINTER; /* return an invalid pointer */ \
203 return p + offset; \
204}
205
206#ifdef __i386__
207/* return the frame pointer of the caller */
208#define GET_CALLER_FP(fp)\
209{\
210 unsigned long *fp1;\
211 __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
212 fp = fp1[0];\
213}
214#else
215#error put code to extract the calling frame pointer
216#endif
217
218/* called when entering a function to add all the local regions */
219void FASTCALL __bound_local_new(void *p1)
220{
221 unsigned long addr, size, fp, *p = p1;
222 GET_CALLER_FP(fp);
223 for(;;) {
224 addr = p[0];
225 if (addr == 0)
226 break;
227 addr += fp;
228 size = p[1];
229 p += 2;
230 __bound_new_region((void *)addr, size);
231 }
232}
233
234/* called when leaving a function to delete all the local regions */
235void FASTCALL __bound_local_delete(void *p1)
236{
237 unsigned long addr, fp, *p = p1;
238 GET_CALLER_FP(fp);
239 for(;;) {
240 addr = p[0];
241 if (addr == 0)
242 break;
243 addr += fp;
244 p += 2;
245 __bound_delete_region((void *)addr);
246 }
247}
248
249#else
250
251void __bound_local_new(void *p)
252{
253}
254void __bound_local_delete(void *p)
255{
256}
257
258void *__bound_ptr_add(void *p, int offset)
259{
260 return p + offset;
261}
262
263#define BOUND_PTR_INDIR(dsize) \
264void *__bound_ptr_indir ## dsize (void *p, int offset) \
265{ \
266 return p + offset; \
267}
268#endif
269
270BOUND_PTR_INDIR(1)
271BOUND_PTR_INDIR(2)
272BOUND_PTR_INDIR(4)
273BOUND_PTR_INDIR(8)
274BOUND_PTR_INDIR(12)
275BOUND_PTR_INDIR(16)
276
277static BoundEntry *__bound_new_page(void)
278{
279 BoundEntry *page;
280 int i;
281
282 page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
283 if (!page)
284 bound_alloc_error();
285 for(i=0;i<BOUND_T2_SIZE;i++) {
286 /* put empty entries */
287 page[i].start = 0;
288 page[i].size = EMPTY_SIZE;
289 page[i].next = NULL;
290 page[i].is_invalid = 0;
291 }
292 return page;
293}
294
295/* currently we use malloc(). Should use bound_new_page() */
296static BoundEntry *bound_new_entry(void)
297{
298 BoundEntry *e;
299 e = libc_malloc(sizeof(BoundEntry));
300 return e;
301}
302
303static void bound_free_entry(BoundEntry *e)
304{
305 libc_free(e);
306}
307
308static inline BoundEntry *get_page(int index)
309{
310 BoundEntry *page;
311 page = __bound_t1[index];
312 if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
313 /* create a new page if necessary */
314 page = __bound_new_page();
315 __bound_t1[index] = page;
316 }
317 return page;
318}
319
320/* mark a region as being invalid (can only be used during init) */
321static void mark_invalid(unsigned long addr, unsigned long size)
322{
323 unsigned long start, end;
324 BoundEntry *page;
325 int t1_start, t1_end, i, j, t2_start, t2_end;
326
327 start = addr;
328 end = addr + size;
329
330 t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
331 if (end != 0)
332 t2_end = end >> BOUND_T3_BITS;
333 else
334 t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
335
336#if 0
337 printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
338#endif
339
340 /* first we handle full pages */
341 t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
342 t1_end = t2_end >> BOUND_T2_BITS;
343
344 i = t2_start & (BOUND_T2_SIZE - 1);
345 j = t2_end & (BOUND_T2_SIZE - 1);
346
347 if (t1_start == t1_end) {
348 page = get_page(t2_start >> BOUND_T2_BITS);
349 for(; i < j; i++) {
350 page[i].size = INVALID_SIZE;
351 page[i].is_invalid = 1;
352 }
353 } else {
354 if (i > 0) {
355 page = get_page(t2_start >> BOUND_T2_BITS);
356 for(; i < BOUND_T2_SIZE; i++) {
357 page[i].size = INVALID_SIZE;
358 page[i].is_invalid = 1;
359 }
360 }
361 for(i = t1_start; i < t1_end; i++) {
362 __bound_t1[i] = __bound_invalid_t2;
363 }
364 if (j != 0) {
365 page = get_page(t1_end);
366 for(i = 0; i < j; i++) {
367 page[i].size = INVALID_SIZE;
368 page[i].is_invalid = 1;
369 }
370 }
371 }
372}
373
374void __bound_init(void)
375{
376 int i;
377 BoundEntry *page;
378 unsigned long start, size;
379 int *p;
380
381 /* save malloc hooks and install bound check hooks */
382 install_malloc_hooks();
383
384#ifndef BOUND_STATIC
385 __bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
386 if (!__bound_t1)
387 bound_alloc_error();
388#endif
389 __bound_empty_t2 = __bound_new_page();
390 for(i=0;i<BOUND_T1_SIZE;i++) {
391 __bound_t1[i] = __bound_empty_t2;
392 }
393
394 page = __bound_new_page();
395 for(i=0;i<BOUND_T2_SIZE;i++) {
396 /* put invalid entries */
397 page[i].start = 0;
398 page[i].size = INVALID_SIZE;
399 page[i].next = NULL;
400 page[i].is_invalid = 1;
401 }
402 __bound_invalid_t2 = page;
403
404 /* invalid pointer zone */
405 start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
406 size = BOUND_T23_SIZE;
407 mark_invalid(start, size);
408
409#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
410 /* malloc zone is also marked invalid. can only use that with
411 hooks because all libs should use the same malloc. The solution
412 would be to build a new malloc for tcc. */
413 start = (unsigned long)&_end;
414 size = 128 * 0x100000;
415 mark_invalid(start, size);
416#endif
417
418 /* add all static bound check values */
419 p = (int *)&__bounds_start;
420 while (p[0] != 0) {
421 __bound_new_region((void *)p[0], p[1]);
422 p += 2;
423 }
424}
425
426static inline void add_region(BoundEntry *e,
427 unsigned long start, unsigned long size)
428{
429 BoundEntry *e1;
430 if (e->start == 0) {
431 /* no region : add it */
432 e->start = start;
433 e->size = size;
434 } else {
435 /* already regions in the list: add it at the head */
436 e1 = bound_new_entry();
437 e1->start = e->start;
438 e1->size = e->size;
439 e1->next = e->next;
440 e->start = start;
441 e->size = size;
442 e->next = e1;
443 }
444}
445
446/* create a new region. It should not already exist in the region list */
447void __bound_new_region(void *p, unsigned long size)
448{
449 unsigned long start, end;
450 BoundEntry *page, *e, *e2;
451 int t1_start, t1_end, i, t2_start, t2_end;
452
453 start = (unsigned long)p;
454 end = start + size;
455 t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
456 t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
457
458 /* start */
459 page = get_page(t1_start);
460 t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
461 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
462 t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
463 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
464#ifdef BOUND_DEBUG
465 printf("new %lx %lx %x %x %x %x\n",
466 start, end, t1_start, t1_end, t2_start, t2_end);
467#endif
468
469 e = (BoundEntry *)((char *)page + t2_start);
470 add_region(e, start, size);
471
472 if (t1_end == t1_start) {
473 /* same ending page */
474 e2 = (BoundEntry *)((char *)page + t2_end);
475 if (e2 > e) {
476 e++;
477 for(;e<e2;e++) {
478 e->start = start;
479 e->size = size;
480 }
481 add_region(e, start, size);
482 }
483 } else {
484 /* mark until end of page */
485 e2 = page + BOUND_T2_SIZE;
486 e++;
487 for(;e<e2;e++) {
488 e->start = start;
489 e->size = size;
490 }
491 /* mark intermediate pages, if any */
492 for(i=t1_start+1;i<t1_end;i++) {
493 page = get_page(i);
494 e2 = page + BOUND_T2_SIZE;
495 for(e=page;e<e2;e++) {
496 e->start = start;
497 e->size = size;
498 }
499 }
500 /* last page */
501 page = get_page(t1_end);
502 e2 = (BoundEntry *)((char *)page + t2_end);
503 for(e=page;e<e2;e++) {
504 e->start = start;
505 e->size = size;
506 }
507 add_region(e, start, size);
508 }
509}
510
511/* delete a region */
512static inline void delete_region(BoundEntry *e,
513 void *p, unsigned long empty_size)
514{
515 unsigned long addr;
516 BoundEntry *e1;
517
518 addr = (unsigned long)p;
519 addr -= e->start;
520 if (addr <= e->size) {
521 /* region found is first one */
522 e1 = e->next;
523 if (e1 == NULL) {
524 /* no more region: mark it empty */
525 e->start = 0;
526 e->size = empty_size;
527 } else {
528 /* copy next region in head */
529 e->start = e1->start;
530 e->size = e1->size;
531 e->next = e1->next;
532 bound_free_entry(e1);
533 }
534 } else {
535 /* find the matching region */
536 for(;;) {
537 e1 = e;
538 e = e->next;
539 /* region not found: do nothing */
540 if (e == NULL)
541 break;
542 addr = (unsigned long)p - e->start;
543 if (addr <= e->size) {
544 /* found: remove entry */
545 e1->next = e->next;
546 bound_free_entry(e);
547 break;
548 }
549 }
550 }
551}
552
553/* WARNING: 'p' must be the starting point of the region. */
554/* return non zero if error */
555int __bound_delete_region(void *p)
556{
557 unsigned long start, end, addr, size, empty_size;
558 BoundEntry *page, *e, *e2;
559 int t1_start, t1_end, t2_start, t2_end, i;
560
561 start = (unsigned long)p;
562 t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
563 t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
564 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
565
566 /* find region size */
567 page = __bound_t1[t1_start];
568 e = (BoundEntry *)((char *)page + t2_start);
569 addr = start - e->start;
570 if (addr > e->size)
571 e = __bound_find_region(e, p);
572 /* test if invalid region */
573 if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
574 return -1;
575 /* compute the size we put in invalid regions */
576 if (e->is_invalid)
577 empty_size = INVALID_SIZE;
578 else
579 empty_size = EMPTY_SIZE;
580 size = e->size;
581 end = start + size;
582
583 /* now we can free each entry */
584 t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
585 t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
586 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
587
588 delete_region(e, p, empty_size);
589 if (t1_end == t1_start) {
590 /* same ending page */
591 e2 = (BoundEntry *)((char *)page + t2_end);
592 if (e2 > e) {
593 e++;
594 for(;e<e2;e++) {
595 e->start = 0;
596 e->size = empty_size;
597 }
598 delete_region(e, p, empty_size);
599 }
600 } else {
601 /* mark until end of page */
602 e2 = page + BOUND_T2_SIZE;
603 e++;
604 for(;e<e2;e++) {
605 e->start = 0;
606 e->size = empty_size;
607 }
608 /* mark intermediate pages, if any */
609 /* XXX: should free them */
610 for(i=t1_start+1;i<t1_end;i++) {
611 page = get_page(i);
612 e2 = page + BOUND_T2_SIZE;
613 for(e=page;e<e2;e++) {
614 e->start = 0;
615 e->size = empty_size;
616 }
617 }
618 /* last page */
619 page = get_page(t2_end);
620 e2 = (BoundEntry *)((char *)page + t2_end);
621 for(e=page;e<e2;e++) {
622 e->start = 0;
623 e->size = empty_size;
624 }
625 delete_region(e, p, empty_size);
626 }
627 return 0;
628}
629
630/* return the size of the region starting at p, or EMPTY_SIZE if non
631 existant region. */
632static unsigned long get_region_size(void *p)
633{
634 unsigned long addr = (unsigned long)p;
635 BoundEntry *e;
636
637 e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
638 e = (BoundEntry *)((char *)e +
639 ((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
640 ((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
641 addr -= e->start;
642 if (addr > e->size)
643 e = __bound_find_region(e, p);
644 if (e->start != (unsigned long)p)
645 return EMPTY_SIZE;
646 return e->size;
647}
648
649/* patched memory functions */
650
651static void install_malloc_hooks(void)
652{
653#ifdef CONFIG_TCC_MALLOC_HOOKS
654 saved_malloc_hook = __malloc_hook;
655 saved_free_hook = __free_hook;
656 saved_realloc_hook = __realloc_hook;
657 saved_memalign_hook = __memalign_hook;
658 __malloc_hook = __bound_malloc;
659 __free_hook = __bound_free;
660 __realloc_hook = __bound_realloc;
661 __memalign_hook = __bound_memalign;
662#endif
663}
664
665static void restore_malloc_hooks(void)
666{
667#ifdef CONFIG_TCC_MALLOC_HOOKS
668 __malloc_hook = saved_malloc_hook;
669 __free_hook = saved_free_hook;
670 __realloc_hook = saved_realloc_hook;
671 __memalign_hook = saved_memalign_hook;
672#endif
673}
674
675static void *libc_malloc(size_t size)
676{
677 void *ptr;
678 restore_malloc_hooks();
679 ptr = malloc(size);
680 install_malloc_hooks();
681 return ptr;
682}
683
684static void libc_free(void *ptr)
685{
686 restore_malloc_hooks();
687 free(ptr);
688 install_malloc_hooks();
689}
690
691/* XXX: we should use a malloc which ensure that it is unlikely that
692 two malloc'ed data have the same address if 'free' are made in
693 between. */
694void *__bound_malloc(size_t size, const void *caller)
695{
696 void *ptr;
697
698 /* we allocate one more byte to ensure the regions will be
699 separated by at least one byte. With the glibc malloc, it may
700 be in fact not necessary */
701 ptr = libc_malloc(size + 1);
702
703 if (!ptr)
704 return NULL;
705 __bound_new_region(ptr, size);
706 return ptr;
707}
708
709void *__bound_memalign(size_t size, size_t align, const void *caller)
710{
711 void *ptr;
712
713 restore_malloc_hooks();
714
715#ifndef HAVE_MEMALIGN
716 if (align > 4) {
717 /* XXX: handle it ? */
718 ptr = NULL;
719 } else {
720 /* we suppose that malloc aligns to at least four bytes */
721 ptr = malloc(size + 1);
722 }
723#else
724 /* we allocate one more byte to ensure the regions will be
725 separated by at least one byte. With the glibc malloc, it may
726 be in fact not necessary */
727 ptr = memalign(size + 1, align);
728#endif
729
730 install_malloc_hooks();
731
732 if (!ptr)
733 return NULL;
734 __bound_new_region(ptr, size);
735 return ptr;
736}
737
738void __bound_free(void *ptr, const void *caller)
739{
740 if (ptr == NULL)
741 return;
742 if (__bound_delete_region(ptr) != 0)
743 bound_error("freeing invalid region");
744
745 libc_free(ptr);
746}
747
748void *__bound_realloc(void *ptr, size_t size, const void *caller)
749{
750 void *ptr1;
751 int old_size;
752
753 if (size == 0) {
754 __bound_free(ptr, caller);
755 return NULL;
756 } else {
757 ptr1 = __bound_malloc(size, caller);
758 if (ptr == NULL || ptr1 == NULL)
759 return ptr1;
760 old_size = get_region_size(ptr);
761 if (old_size == EMPTY_SIZE)
762 bound_error("realloc'ing invalid pointer");
763 memcpy(ptr1, ptr, old_size);
764 __bound_free(ptr, caller);
765 return ptr1;
766 }
767}
768
769#ifndef CONFIG_TCC_MALLOC_HOOKS
770void *__bound_calloc(size_t nmemb, size_t size)
771{
772 void *ptr;
773 size = size * nmemb;
774 ptr = __bound_malloc(size, NULL);
775 if (!ptr)
776 return NULL;
777 memset(ptr, 0, size);
778 return ptr;
779}
780#endif
781
782#if 0
783static void bound_dump(void)
784{
785 BoundEntry *page, *e;
786 int i, j;
787
788 printf("region dump:\n");
789 for(i=0;i<BOUND_T1_SIZE;i++) {
790 page = __bound_t1[i];
791 for(j=0;j<BOUND_T2_SIZE;j++) {
792 e = page + j;
793 /* do not print invalid or empty entries */
794 if (e->size != EMPTY_SIZE && e->start != 0) {
795 printf("%08x:",
796 (i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
797 (j << BOUND_T3_BITS));
798 do {
799 printf(" %08lx:%08lx", e->start, e->start + e->size);
800 e = e->next;
801 } while (e != NULL);
802 printf("\n");
803 }
804 }
805 }
806}
807#endif
808
809/* some useful checked functions */
810
811/* check that (p ... p + size - 1) lies inside 'p' region, if any */
812static void __bound_check(const void *p, size_t size)
813{
814 if (size == 0)
815 return;
816 p = __bound_ptr_add((void *)p, size);
817 if (p == INVALID_POINTER)
818 bound_error("invalid pointer");
819}
820
821void *__bound_memcpy(void *dst, const void *src, size_t size)
822{
823 __bound_check(dst, size);
824 __bound_check(src, size);
825 /* check also region overlap */
826 if (src >= dst && src < dst + size)
827 bound_error("overlapping regions in memcpy()");
828 return memcpy(dst, src, size);
829}
830
831void *__bound_memmove(void *dst, const void *src, size_t size)
832{
833 __bound_check(dst, size);
834 __bound_check(src, size);
835 return memmove(dst, src, size);
836}
837
838void *__bound_memset(void *dst, int c, size_t size)
839{
840 __bound_check(dst, size);
841 return memset(dst, c, size);
842}
843
844/* XXX: could be optimized */
845int __bound_strlen(const char *s)
846{
847 const char *p;
848 int len;
849
850 len = 0;
851 for(;;) {
852 p = __bound_ptr_indir1((char *)s, len);
853 if (p == INVALID_POINTER)
854 bound_error("bad pointer in strlen()");
855 if (*p == '\0')
856 break;
857 len++;
858 }
859 return len;
860}
861
862char *__bound_strcpy(char *dst, const char *src)
863{
864 int len;
865 len = __bound_strlen(src);
866 return __bound_memcpy(dst, src, len + 1);
867}
868
lib/libtcc1.c+607−0
@@ -0,0 +1,607 @@
1/* TCC runtime library.
2 Parts of this code are (c) 2002 Fabrice Bellard
3
4 Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
5
6This file is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11In addition to the permissions in the GNU General Public License, the
12Free Software Foundation gives you unlimited permission to link the
13compiled version of this file into combinations with other programs,
14and to distribute those combinations without any restriction coming
15from the use of this file. (The General Public License restrictions
16do apply in other respects; for example, they cover modification of
17the file, and distribution when not linked into a combine
18executable.)
19
20This file is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; see the file COPYING. If not, write to
27the Free Software Foundation, 59 Temple Place - Suite 330,
28Boston, MA 02111-1307, USA.
29*/
30
31#define W_TYPE_SIZE 32
32#define BITS_PER_UNIT 8
33
34typedef int Wtype;
35typedef unsigned int UWtype;
36typedef unsigned int USItype;
37typedef long long DWtype;
38typedef unsigned long long UDWtype;
39
40struct DWstruct {
41 Wtype low, high;
42};
43
44typedef union
45{
46 struct DWstruct s;
47 DWtype ll;
48} DWunion;
49
50typedef long double XFtype;
51#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
52#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
53
54/* the following deal with IEEE single-precision numbers */
55#define EXCESS 126
56#define SIGNBIT 0x80000000
57#define HIDDEN (1 << 23)
58#define SIGN(fp) ((fp) & SIGNBIT)
59#define EXP(fp) (((fp) >> 23) & 0xFF)
60#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN)
61#define PACK(s,e,m) ((s) | ((e) << 23) | (m))
62
63/* the following deal with IEEE double-precision numbers */
64#define EXCESSD 1022
65#define HIDDEND (1 << 20)
66#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
67#define SIGND(fp) ((fp.l.upper) & SIGNBIT)
68#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
69 (fp.l.lower >> 22))
70#define HIDDEND_LL ((long long)1 << 52)
71#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
72#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
73
74/* the following deal with x86 long double-precision numbers */
75#define EXCESSLD 16382
76#define EXPLD(fp) (fp.l.upper & 0x7fff)
77#define SIGNLD(fp) ((fp.l.upper) & 0x8000)
78
79/* only for x86 */
80union ldouble_long {
81 long double ld;
82 struct {
83 unsigned long long lower;
84 unsigned short upper;
85 } l;
86};
87
88union double_long {
89 double d;
90#if 1
91 struct {
92 unsigned int lower;
93 int upper;
94 } l;
95#else
96 struct {
97 int upper;
98 unsigned int lower;
99 } l;
100#endif
101 long long ll;
102};
103
104union float_long {
105 float f;
106 long l;
107};
108
109/* XXX: we don't support several builtin supports for now */
110#ifndef __x86_64__
111
112/* XXX: use gcc/tcc intrinsic ? */
113#if defined(__i386__)
114#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
115 __asm__ ("subl %5,%1\n\tsbbl %3,%0" \
116 : "=r" ((USItype) (sh)), \
117 "=&r" ((USItype) (sl)) \
118 : "0" ((USItype) (ah)), \
119 "g" ((USItype) (bh)), \
120 "1" ((USItype) (al)), \
121 "g" ((USItype) (bl)))
122#define umul_ppmm(w1, w0, u, v) \
123 __asm__ ("mull %3" \
124 : "=a" ((USItype) (w0)), \
125 "=d" ((USItype) (w1)) \
126 : "%0" ((USItype) (u)), \
127 "rm" ((USItype) (v)))
128#define udiv_qrnnd(q, r, n1, n0, dv) \
129 __asm__ ("divl %4" \
130 : "=a" ((USItype) (q)), \
131 "=d" ((USItype) (r)) \
132 : "0" ((USItype) (n0)), \
133 "1" ((USItype) (n1)), \
134 "rm" ((USItype) (dv)))
135#define count_leading_zeros(count, x) \
136 do { \
137 USItype __cbtmp; \
138 __asm__ ("bsrl %1,%0" \
139 : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
140 (count) = __cbtmp ^ 31; \
141 } while (0)
142#else
143#error unsupported CPU type
144#endif
145
146/* most of this code is taken from libgcc2.c from gcc */
147
148static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
149{
150 DWunion ww;
151 DWunion nn, dd;
152 DWunion rr;
153 UWtype d0, d1, n0, n1, n2;
154 UWtype q0, q1;
155 UWtype b, bm;
156
157 nn.ll = n;
158 dd.ll = d;
159
160 d0 = dd.s.low;
161 d1 = dd.s.high;
162 n0 = nn.s.low;
163 n1 = nn.s.high;
164
165#if !UDIV_NEEDS_NORMALIZATION
166 if (d1 == 0)
167 {
168 if (d0 > n1)
169 {
170 /* 0q = nn / 0D */
171
172 udiv_qrnnd (q0, n0, n1, n0, d0);
173 q1 = 0;
174
175 /* Remainder in n0. */
176 }
177 else
178 {
179 /* qq = NN / 0d */
180
181 if (d0 == 0)
182 d0 = 1 / d0; /* Divide intentionally by zero. */
183
184 udiv_qrnnd (q1, n1, 0, n1, d0);
185 udiv_qrnnd (q0, n0, n1, n0, d0);
186
187 /* Remainder in n0. */
188 }
189
190 if (rp != 0)
191 {
192 rr.s.low = n0;
193 rr.s.high = 0;
194 *rp = rr.ll;
195 }
196 }
197
198#else /* UDIV_NEEDS_NORMALIZATION */
199
200 if (d1 == 0)
201 {
202 if (d0 > n1)
203 {
204 /* 0q = nn / 0D */
205
206 count_leading_zeros (bm, d0);
207
208 if (bm != 0)
209 {
210 /* Normalize, i.e. make the most significant bit of the
211 denominator set. */
212
213 d0 = d0 << bm;
214 n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
215 n0 = n0 << bm;
216 }
217
218 udiv_qrnnd (q0, n0, n1, n0, d0);
219 q1 = 0;
220
221 /* Remainder in n0 >> bm. */
222 }
223 else
224 {
225 /* qq = NN / 0d */
226
227 if (d0 == 0)
228 d0 = 1 / d0; /* Divide intentionally by zero. */
229
230 count_leading_zeros (bm, d0);
231
232 if (bm == 0)
233 {
234 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
235 conclude (the most significant bit of n1 is set) /\ (the
236 leading quotient digit q1 = 1).
237
238 This special case is necessary, not an optimization.
239 (Shifts counts of W_TYPE_SIZE are undefined.) */
240
241 n1 -= d0;
242 q1 = 1;
243 }
244 else
245 {
246 /* Normalize. */
247
248 b = W_TYPE_SIZE - bm;
249
250 d0 = d0 << bm;
251 n2 = n1 >> b;
252 n1 = (n1 << bm) | (n0 >> b);
253 n0 = n0 << bm;
254
255 udiv_qrnnd (q1, n1, n2, n1, d0);
256 }
257
258 /* n1 != d0... */
259
260 udiv_qrnnd (q0, n0, n1, n0, d0);
261
262 /* Remainder in n0 >> bm. */
263 }
264
265 if (rp != 0)
266 {
267 rr.s.low = n0 >> bm;
268 rr.s.high = 0;
269 *rp = rr.ll;
270 }
271 }
272#endif /* UDIV_NEEDS_NORMALIZATION */
273
274 else
275 {
276 if (d1 > n1)
277 {
278 /* 00 = nn / DD */
279
280 q0 = 0;
281 q1 = 0;
282
283 /* Remainder in n1n0. */
284 if (rp != 0)
285 {
286 rr.s.low = n0;
287 rr.s.high = n1;
288 *rp = rr.ll;
289 }
290 }
291 else
292 {
293 /* 0q = NN / dd */
294
295 count_leading_zeros (bm, d1);
296 if (bm == 0)
297 {
298 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
299 conclude (the most significant bit of n1 is set) /\ (the
300 quotient digit q0 = 0 or 1).
301
302 This special case is necessary, not an optimization. */
303
304 /* The condition on the next line takes advantage of that
305 n1 >= d1 (true due to program flow). */
306 if (n1 > d1 || n0 >= d0)
307 {
308 q0 = 1;
309 sub_ddmmss (n1, n0, n1, n0, d1, d0);
310 }
311 else
312 q0 = 0;
313
314 q1 = 0;
315
316 if (rp != 0)
317 {
318 rr.s.low = n0;
319 rr.s.high = n1;
320 *rp = rr.ll;
321 }
322 }
323 else
324 {
325 UWtype m1, m0;
326 /* Normalize. */
327
328 b = W_TYPE_SIZE - bm;
329
330 d1 = (d1 << bm) | (d0 >> b);
331 d0 = d0 << bm;
332 n2 = n1 >> b;
333 n1 = (n1 << bm) | (n0 >> b);
334 n0 = n0 << bm;
335
336 udiv_qrnnd (q0, n1, n2, n1, d1);
337 umul_ppmm (m1, m0, q0, d0);
338
339 if (m1 > n1 || (m1 == n1 && m0 > n0))
340 {
341 q0--;
342 sub_ddmmss (m1, m0, m1, m0, d1, d0);
343 }
344
345 q1 = 0;
346
347 /* Remainder in (n1n0 - m1m0) >> bm. */
348 if (rp != 0)
349 {
350 sub_ddmmss (n1, n0, n1, n0, m1, m0);
351 rr.s.low = (n1 << b) | (n0 >> bm);
352 rr.s.high = n1 >> bm;
353 *rp = rr.ll;
354 }
355 }
356 }
357 }
358
359 ww.s.low = q0;
360 ww.s.high = q1;
361 return ww.ll;
362}
363
364#define __negdi2(a) (-(a))
365
366long long __divdi3(long long u, long long v)
367{
368 int c = 0;
369 DWunion uu, vv;
370 DWtype w;
371
372 uu.ll = u;
373 vv.ll = v;
374
375 if (uu.s.high < 0) {
376 c = ~c;
377 uu.ll = __negdi2 (uu.ll);
378 }
379 if (vv.s.high < 0) {
380 c = ~c;
381 vv.ll = __negdi2 (vv.ll);
382 }
383 w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
384 if (c)
385 w = __negdi2 (w);
386 return w;
387}
388
389long long __moddi3(long long u, long long v)
390{
391 int c = 0;
392 DWunion uu, vv;
393 DWtype w;
394
395 uu.ll = u;
396 vv.ll = v;
397
398 if (uu.s.high < 0) {
399 c = ~c;
400 uu.ll = __negdi2 (uu.ll);
401 }
402 if (vv.s.high < 0)
403 vv.ll = __negdi2 (vv.ll);
404
405 __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
406 if (c)
407 w = __negdi2 (w);
408 return w;
409}
410
411unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
412{
413 return __udivmoddi4 (u, v, (UDWtype *) 0);
414}
415
416unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
417{
418 UDWtype w;
419
420 __udivmoddi4 (u, v, &w);
421 return w;
422}
423
424/* XXX: fix tcc's code generator to do this instead */
425long long __ashrdi3(long long a, int b)
426{
427#ifdef __TINYC__
428 DWunion u;
429 u.ll = a;
430 if (b >= 32) {
431 u.s.low = u.s.high >> (b - 32);
432 u.s.high = u.s.high >> 31;
433 } else if (b != 0) {
434 u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
435 u.s.high = u.s.high >> b;
436 }
437 return u.ll;
438#else
439 return a >> b;
440#endif
441}
442
443/* XXX: fix tcc's code generator to do this instead */
444unsigned long long __lshrdi3(unsigned long long a, int b)
445{
446#ifdef __TINYC__
447 DWunion u;
448 u.ll = a;
449 if (b >= 32) {
450 u.s.low = (unsigned)u.s.high >> (b - 32);
451 u.s.high = 0;
452 } else if (b != 0) {
453 u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
454 u.s.high = (unsigned)u.s.high >> b;
455 }
456 return u.ll;
457#else
458 return a >> b;
459#endif
460}
461
462/* XXX: fix tcc's code generator to do this instead */
463long long __ashldi3(long long a, int b)
464{
465#ifdef __TINYC__
466 DWunion u;
467 u.ll = a;
468 if (b >= 32) {
469 u.s.high = (unsigned)u.s.low << (b - 32);
470 u.s.low = 0;
471 } else if (b != 0) {
472 u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
473 u.s.low = (unsigned)u.s.low << b;
474 }
475 return u.ll;
476#else
477 return a << b;
478#endif
479}
480
481#if defined(__i386__)
482/* FPU control word for rounding to nearest mode */
483unsigned short __tcc_fpu_control = 0x137f;
484/* FPU control word for round to zero mode for int conversion */
485unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
486#endif
487
488#endif /* !__x86_64__ */
489
490/* XXX: fix tcc's code generator to do this instead */
491float __floatundisf(unsigned long long a)
492{
493 DWunion uu;
494 XFtype r;
495
496 uu.ll = a;
497 if (uu.s.high >= 0) {
498 return (float)uu.ll;
499 } else {
500 r = (XFtype)uu.ll;
501 r += 18446744073709551616.0;
502 return (float)r;
503 }
504}
505
506double __floatundidf(unsigned long long a)
507{
508 DWunion uu;
509 XFtype r;
510
511 uu.ll = a;
512 if (uu.s.high >= 0) {
513 return (double)uu.ll;
514 } else {
515 r = (XFtype)uu.ll;
516 r += 18446744073709551616.0;
517 return (double)r;
518 }
519}
520
521long double __floatundixf(unsigned long long a)
522{
523 DWunion uu;
524 XFtype r;
525
526 uu.ll = a;
527 if (uu.s.high >= 0) {
528 return (long double)uu.ll;
529 } else {
530 r = (XFtype)uu.ll;
531 r += 18446744073709551616.0;
532 return (long double)r;
533 }
534}
535
536unsigned long long __fixunssfdi (float a1)
537{
538 register union float_long fl1;
539 register int exp;
540 register unsigned long l;
541
542 fl1.f = a1;
543
544 if (fl1.l == 0)
545 return (0);
546
547 exp = EXP (fl1.l) - EXCESS - 24;
548
549 l = MANT(fl1.l);
550 if (exp >= 41)
551 return (unsigned long long)-1;
552 else if (exp >= 0)
553 return (unsigned long long)l << exp;
554 else if (exp >= -23)
555 return l >> -exp;
556 else
557 return 0;
558}
559
560unsigned long long __fixunsdfdi (double a1)
561{
562 register union double_long dl1;
563 register int exp;
564 register unsigned long long l;
565
566 dl1.d = a1;
567
568 if (dl1.ll == 0)
569 return (0);
570
571 exp = EXPD (dl1) - EXCESSD - 53;
572
573 l = MANTD_LL(dl1);
574
575 if (exp >= 12)
576 return (unsigned long long)-1;
577 else if (exp >= 0)
578 return l << exp;
579 else if (exp >= -52)
580 return l >> -exp;
581 else
582 return 0;
583}
584
585unsigned long long __fixunsxfdi (long double a1)
586{
587 register union ldouble_long dl1;
588 register int exp;
589 register unsigned long long l;
590
591 dl1.ld = a1;
592
593 if (dl1.l.lower == 0 && dl1.l.upper == 0)
594 return (0);
595
596 exp = EXPLD (dl1) - EXCESSLD - 64;
597
598 l = dl1.l.lower;
599
600 if (exp > 0)
601 return (unsigned long long)-1;
602 else if (exp >= -63)
603 return l >> -exp;
604 else
605 return 0;
606}
607