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
17+p4:
18+ cmp $4096,%eax
19+ jle p5
20+ sub $4096,%esp
21+ sub $4096,%eax
22+ test %eax,(%esp)
23+ jmp p4
24+
25+p5:
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+
40+p6:
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
16+p1:
17+ cmp $4096,%eax
18+ jle p2
19+ sub $4096,%esp
20+ sub $4096,%eax
21+ test %eax,(%esp)
22+ jmp p1
23+p2:
24+#endif
25+
26+ sub %eax,%esp
27+ mov %esp,%eax
28+p3:
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+
66+typedef 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 */
74+void __bound_init(void);
75+void __bound_new_region(void *p, unsigned long size);
76+int __bound_delete_region(void *p);
77+
78+#define FASTCALL __attribute__((regparm(3)))
79+
80+void *__bound_malloc(size_t size, const void *caller);
81+void *__bound_memalign(size_t size, size_t align, const void *caller);
82+void __bound_free(void *ptr, const void *caller);
83+void *__bound_realloc(void *ptr, size_t size, const void *caller);
84+static void *libc_malloc(size_t size);
85+static void libc_free(void *ptr);
86+static void install_malloc_hooks(void);
87+static void restore_malloc_hooks(void);
88+
89+#ifdef CONFIG_TCC_MALLOC_HOOKS
90+static void *saved_malloc_hook;
91+static void *saved_free_hook;
92+static void *saved_realloc_hook;
93+static void *saved_memalign_hook;
94+#endif
95+
96+/* linker definitions */
97+extern char _end;
98+
99+/* TCC definitions */
100+extern char __bounds_start; /* start of static bounds table */
101+/* error message, just for TCC */
102+const char *__bound_error_msg;
103+
104+/* runtime error output */
105+extern void rt_error(unsigned long pc, const char *fmt, ...);
106+
107+#ifdef BOUND_STATIC
108+static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
109+#else
110+static BoundEntry **__bound_t1; /* page table */
111+#endif
112+static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
113+static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
114+
115+static 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 */
144+static void bound_error(const char *fmt, ...)
145+{
146+ __bound_error_msg = fmt;
147+ *(int *)0 = 0; /* force a runtime error */
148+}
149+
150+static 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 */
160+void * 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) \
186+void * 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 */
219+void 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 */
235+void 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+
251+void __bound_local_new(void *p)
252+{
253+}
254+void __bound_local_delete(void *p)
255+{
256+}
257+
258+void *__bound_ptr_add(void *p, int offset)
259+{
260+ return p + offset;
261+}
262+
263+#define BOUND_PTR_INDIR(dsize) \
264+void *__bound_ptr_indir ## dsize (void *p, int offset) \
265+{ \
266+ return p + offset; \
267+}
268+#endif
269+
270+BOUND_PTR_INDIR(1)
271+BOUND_PTR_INDIR(2)
272+BOUND_PTR_INDIR(4)
273+BOUND_PTR_INDIR(8)
274+BOUND_PTR_INDIR(12)
275+BOUND_PTR_INDIR(16)
276+
277+static 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() */
296+static BoundEntry *bound_new_entry(void)
297+{
298+ BoundEntry *e;
299+ e = libc_malloc(sizeof(BoundEntry));
300+ return e;
301+}
302+
303+static void bound_free_entry(BoundEntry *e)
304+{
305+ libc_free(e);
306+}
307+
308+static 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) */
321+static 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+
374+void __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+
426+static 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 */
447+void __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 */
512+static 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 */
555+int __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. */
632+static 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+
651+static 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+
665+static 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+
675+static 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+
684+static 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. */
694+void *__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+
709+void *__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+
738+void __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+
748+void *__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
770+void *__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
783+static 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 */
812+static 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+
821+void *__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+
831+void *__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+
838+void *__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 */
845+int __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+
862+char *__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+
6+This file is free software; you can redistribute it and/or modify it
7+under the terms of the GNU General Public License as published by the
8+Free Software Foundation; either version 2, or (at your option) any
9+later version.
10+
11+In addition to the permissions in the GNU General Public License, the
12+Free Software Foundation gives you unlimited permission to link the
13+compiled version of this file into combinations with other programs,
14+and to distribute those combinations without any restriction coming
15+from the use of this file. (The General Public License restrictions
16+do apply in other respects; for example, they cover modification of
17+the file, and distribution when not linked into a combine
18+executable.)
19+
20+This file is distributed in the hope that it will be useful, but
21+WITHOUT ANY WARRANTY; without even the implied warranty of
22+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23+General Public License for more details.
24+
25+You should have received a copy of the GNU General Public License
26+along with this program; see the file COPYING. If not, write to
27+the Free Software Foundation, 59 Temple Place - Suite 330,
28+Boston, MA 02111-1307, USA.
29+*/
30+
31+#define W_TYPE_SIZE 32
32+#define BITS_PER_UNIT 8
33+
34+typedef int Wtype;
35+typedef unsigned int UWtype;
36+typedef unsigned int USItype;
37+typedef long long DWtype;
38+typedef unsigned long long UDWtype;
39+
40+struct DWstruct {
41+ Wtype low, high;
42+};
43+
44+typedef union
45+{
46+ struct DWstruct s;
47+ DWtype ll;
48+} DWunion;
49+
50+typedef 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 */
80+union ldouble_long {
81+ long double ld;
82+ struct {
83+ unsigned long long lower;
84+ unsigned short upper;
85+ } l;
86+};
87+
88+union 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+
104+union 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+
148+static 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+
366+long 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+
389+long 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+
411+unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
412+{
413+ return __udivmoddi4 (u, v, (UDWtype *) 0);
414+}
415+
416+unsigned 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 */
425+long 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 */
444+unsigned 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 */
463+long 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 */
483+unsigned short __tcc_fpu_control = 0x137f;
484+/* FPU control word for round to zero mode for int conversion */
485+unsigned 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 */
491+float __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+
506+double __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+
521+long 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+
536+unsigned 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+
560+unsigned 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+
585+unsigned 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+