📄 libgcc2.c
字号:
asm (" adds 80,%sp,%r16"); /* compute the address of the new va_list structure. Put in into r16 so that it will be returned to the caller. */ /* Initialize all fields of the new va_list structure. This structure looks like: typedef struct { unsigned long ireg_used; unsigned long freg_used; long *reg_base; long *mem_ptr; } va_list; */ asm (" st.l %r0, 0(%r16)"); /* nfixed */ asm (" st.l %r0, 4(%r16)"); /* nfloating */ asm (" st.l %sp, 8(%r16)"); /* __va_ctl points to __va_struct. */ asm (" bri %r1"); /* delayed return */ asm (" st.l %r28,12(%r16)"); /* pointer to overflow args */#else /* not __svr4__ */#if defined(__PARAGON__) /* * we'll use SVR4-ish varargs but need SVR3.2 assembler syntax, * and we stand a better chance of hooking into libraries * compiled by PGI. [andyp@ssd.intel.com] */ asm (" .text"); asm (" .align 4"); asm (".globl __builtin_saveregs");asm ("__builtin_saveregs:"); asm (".globl ___builtin_saveregs");asm ("___builtin_saveregs:"); asm (" andnot 0x0f,sp,sp"); /* round down to 16-byte boundary */ asm (" adds -96,sp,sp"); /* allocate stack space for reg save area and also for a new va_list structure */ /* Save all argument registers in the arg reg save area. The arg reg save area must have the following layout (according to the svr4 ABI): struct { union { float freg[8]; double dreg[4]; } float_regs; long ireg[12]; }; */ asm (" fst.q f8, 0(sp)"); asm (" fst.q f12,16(sp)"); asm (" st.l r16,32(sp)"); asm (" st.l r17,36(sp)"); asm (" st.l r18,40(sp)"); asm (" st.l r19,44(sp)"); asm (" st.l r20,48(sp)"); asm (" st.l r21,52(sp)"); asm (" st.l r22,56(sp)"); asm (" st.l r23,60(sp)"); asm (" st.l r24,64(sp)"); asm (" st.l r25,68(sp)"); asm (" st.l r26,72(sp)"); asm (" st.l r27,76(sp)"); asm (" adds 80,sp,r16"); /* compute the address of the new va_list structure. Put in into r16 so that it will be returned to the caller. */ /* Initialize all fields of the new va_list structure. This structure looks like: typedef struct { unsigned long ireg_used; unsigned long freg_used; long *reg_base; long *mem_ptr; } va_list; */ asm (" st.l r0, 0(r16)"); /* nfixed */ asm (" st.l r0, 4(r16)"); /* nfloating */ asm (" st.l sp, 8(r16)"); /* __va_ctl points to __va_struct. */ asm (" bri r1"); /* delayed return */ asm (" st.l r28,12(r16)"); /* pointer to overflow args */#else /* not __PARAGON__ */ asm (" .text"); asm (" .align 4"); asm (".globl ___builtin_saveregs"); asm ("___builtin_saveregs:"); asm (" mov sp,r30"); asm (" andnot 0x0f,sp,sp"); asm (" adds -96,sp,sp"); /* allocate sufficient space on the stack *//* Fill in the __va_struct. */ asm (" st.l r16, 0(sp)"); /* save integer regs (r16-r27) */ asm (" st.l r17, 4(sp)"); /* int fixed[12] */ asm (" st.l r18, 8(sp)"); asm (" st.l r19,12(sp)"); asm (" st.l r20,16(sp)"); asm (" st.l r21,20(sp)"); asm (" st.l r22,24(sp)"); asm (" st.l r23,28(sp)"); asm (" st.l r24,32(sp)"); asm (" st.l r25,36(sp)"); asm (" st.l r26,40(sp)"); asm (" st.l r27,44(sp)"); asm (" fst.q f8, 48(sp)"); /* save floating regs (f8-f15) */ asm (" fst.q f12,64(sp)"); /* int floating[8] *//* Fill in the __va_ctl. */ asm (" st.l sp, 80(sp)"); /* __va_ctl points to __va_struct. */ asm (" st.l r28,84(sp)"); /* pointer to more args */ asm (" st.l r0, 88(sp)"); /* nfixed */ asm (" st.l r0, 92(sp)"); /* nfloating */ asm (" adds 80,sp,r16"); /* return address of the __va_ctl. */ asm (" bri r1"); asm (" mov r30,sp"); /* recover stack and pass address to start of data. */#endif /* not __PARAGON__ */#endif /* not __svr4__ */#else /* not __i860__ */#ifdef __sparc__ asm (".global __builtin_saveregs"); asm ("__builtin_saveregs:"); asm (".global ___builtin_saveregs"); asm ("___builtin_saveregs:");#ifdef NEED_PROC_COMMAND asm (".proc 020");#endif asm ("st %i0,[%fp+68]"); asm ("st %i1,[%fp+72]"); asm ("st %i2,[%fp+76]"); asm ("st %i3,[%fp+80]"); asm ("st %i4,[%fp+84]"); asm ("retl"); asm ("st %i5,[%fp+88]");#ifdef NEED_TYPE_COMMAND asm (".type __builtin_saveregs,#function"); asm (".size __builtin_saveregs,.-__builtin_saveregs");#endif#else /* not __sparc__ */#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__) asm (" .text"); asm (" .ent __builtin_saveregs"); asm (" .globl __builtin_saveregs"); asm ("__builtin_saveregs:"); asm (" sw $4,0($30)"); asm (" sw $5,4($30)"); asm (" sw $6,8($30)"); asm (" sw $7,12($30)"); asm (" j $31"); asm (" .end __builtin_saveregs");#else /* not __mips__, etc. */void *__builtin_saveregs (){ abort ();}#endif /* not __mips__ */#endif /* not __sparc__ */#endif /* not __i860__ */#endif#ifdef L_eprintf#ifndef inhibit_libc#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */#include <stdio.h>/* This is used by the `assert' macro. */void__eprintf (string, expression, line, filename) const char *string; const char *expression; int line; const char *filename;{ fprintf (stderr, string, expression, line, filename); fflush (stderr); abort ();}#endif#endif#ifdef L_bb/* Structure emitted by -a */struct bb{ long zero_word; const char *filename; long *counts; long ncounts; struct bb *next; const unsigned long *addresses; /* Older GCC's did not emit these fields. */ long nwords; const char **functions; const long *line_nums; const char **filenames;};#ifdef BLOCK_PROFILER_CODEBLOCK_PROFILER_CODE#else#ifndef inhibit_libc/* Simple minded basic block profiling output dumper for systems that don't provide tcov support. At present, it requires atexit and stdio. */#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */#include <stdio.h>char *ctime ();#ifdef HAVE_ATEXIT#ifdef WINNTextern int atexit (void (*) (void));#elseextern void atexit (void (*) (void));#endif#define ON_EXIT(FUNC,ARG) atexit ((FUNC))#else#ifdef sunextern void on_exit (void*, void*);#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))#endif#endifstatic struct bb *bb_head;/* Return the number of digits needed to print a value *//* __inline__ */ static int num_digits (long value, int base){ int minus = (value < 0 && base != 16); unsigned long v = (minus) ? -value : value; int ret = minus; do { v /= base; ret++; } while (v); return ret;}void__bb_exit_func (void){ FILE *file = fopen ("bb.out", "a"); long time_value; if (!file) perror ("bb.out"); else { struct bb *ptr; /* This is somewhat type incorrect, but it avoids worrying about exactly where time.h is included from. It should be ok unless a void * differs from other pointer formats, or if sizeof(long) is < sizeof (time_t). It would be nice if we could assume the use of rationale standards here. */ time((void *) &time_value); fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value)); /* We check the length field explicitly in order to allow compatibility with older GCC's which did not provide it. */ for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next) { int i; int func_p = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000); int line_p = (func_p && ptr->line_nums); int file_p = (func_p && ptr->filenames); long ncounts = ptr->ncounts; long cnt_max = 0; long line_max = 0; long addr_max = 0; int file_len = 0; int func_len = 0; int blk_len = num_digits (ncounts, 10); int cnt_len; int line_len; int addr_len; fprintf (file, "File %s, %ld basic blocks \n\n", ptr->filename, ncounts); /* Get max values for each field. */ for (i = 0; i < ncounts; i++) { const char *p; int len; if (cnt_max < ptr->counts[i]) cnt_max = ptr->counts[i]; if (addr_max < ptr->addresses[i]) addr_max = ptr->addresses[i]; if (line_p && line_max < ptr->line_nums[i]) line_max = ptr->line_nums[i]; if (func_p) { p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>"; len = strlen (p); if (func_len < len) func_len = len; } if (file_p) { p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>"; len = strlen (p); if (file_len < len) file_len = len; } } addr_len = num_digits (addr_max, 16); cnt_len = num_digits (cnt_max, 10); line_len = num_digits (line_max, 10); /* Now print out the basic block information. */ for (i = 0; i < ncounts; i++) { fprintf (file, " Block #%*d: executed %*ld time(s) address= 0x%.*lx", blk_len, i+1, cnt_len, ptr->counts[i], addr_len, ptr->addresses[i]); if (func_p) fprintf (file, " function= %-*s", func_len, (ptr->functions[i]) ? ptr->functions[i] : "<none>"); if (line_p) fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]); if (file_p) fprintf (file, " file= %s", (ptr->filenames[i]) ? ptr->filenames[i] : "<none>"); fprintf (file, "\n"); } fprintf (file, "\n"); fflush (file); } fprintf (file, "\n\n"); fclose (file); }}void__bb_init_func (struct bb *blocks){ /* User is supposed to check whether the first word is non-0, but just in case.... */ if (blocks->zero_word) return;#ifdef ON_EXIT /* Initialize destructor. */ if (!bb_head) ON_EXIT (__bb_exit_func, 0);#endif /* Set up linked list. */ blocks->zero_word = 1; blocks->next = bb_head; bb_head = blocks;}#endif /* not inhibit_libc */#endif /* not BLOCK_PROFILER_CODE */#endif /* L_bb *//* Default free-store management functions for C++, per sections 12.5 and 17.3.3 of the Working Paper. */#ifdef L_op_new/* operator new (size_t), described in 17.3.3.5. This function is used by C++ programs to allocate a block of memory to hold a single object. */typedef void (*vfp)(void);extern vfp __new_handler;extern void __default_new_handler (void);#ifdef WEAK_ALIASvoid * __builtin_new (size_t sz) __attribute__ ((weak, alias ("___builtin_new")));void *___builtin_new (size_t sz)#elsevoid *__builtin_new (size_t sz)#endif{ void *p; vfp handler = (__new_handler) ? __new_handler : __default_new_handler; /* malloc (0) is unpredictable; avoid it. */ if (sz == 0) sz = 1; p = (void *) malloc (sz); while (p == 0) { (*handler) (); p = (void *) malloc (sz); } return p;}#endif /* L_op_new */#ifdef L_op_vnew/* void * operator new [] (size_t), described in 17.3.3.6. This function is used by C++ programs to allocate a block of memory for an array. */extern void * __builtin_new (size_t);#ifdef WEAK_ALIASvoid * __builtin_vec_new (size_t sz) __attribute__ ((weak, alias ("___builtin_vec_new")));void *___builtin_vec_new (size_t sz)#elsevoid *__builtin_vec_new (size_t sz)#endif{ return __builtin_new (sz);}#endif /* L_op_vnew */#ifdef L_new_handler/* set_new_handler (fvoid_t *) and the default new handler, described in 17.3.3.2 and 17.3.3.5. These functions define the result of a failure to allocate the amount of memory requested from operator new or new []. */#ifndef inhibit_libc/* This gets us __GNU_LIBRARY__. */#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */#include <stdio.h>#ifdef __GNU_LIBRARY__ /* Avoid forcing the library's meaning of `write' on the user program by using the "internal" name (for use within the library) */#define write(fd, buf, n) __write((fd), (buf), (n))#endif#endif /* inhibit_libc */typedef void (*vfp)(void);void __default_new_handler (void);vfp __new_handler = (vfp)0;vfpset_new_handler (vfp handler){ vfp prev_handler; prev_handler = __new_handler; if (handler == 0) handler = __default_new_handler; __new_handler = handler; return prev_handler;}#define MESSAGE "Virtual memory exceeded in `new'\n"void__default_new_handler (){#ifndef inhibit_libc /* don't use fprintf (stderr, ...) because it may need to call malloc. */ /* This should really print the name of the program, but that is hard to do. We need a standard, clean way to get at the name. */ write (2, MESSAGE, sizeof (MESSAGE));#endif /* don't call exit () because that may call global destructors which may cause a loop. */ _exit (-1);}#endif#ifdef L_op_delete/* operator delete (void *), described in 17.3.3.3. This function is used by C++ programs to return to the free store a block of memory allocated as a single object. */#ifdef WEAK_ALIASvoid __builtin_delete (void *ptr) __attribute__ ((weak, alias ("___builtin_delete")));void___builtin_delete (void *ptr)#elsevoid__builtin_delete (void *ptr)#endif{ if (ptr) free (ptr);}#endif#ifdef L_op_vdel/* operator delete [] (void *), described in 17.3.3.4. This function is used by C++ programs to return to the free store a block of memory allocated as an array. */extern void __builtin_delete (void *);#ifdef WEAK_ALIASvoid __builtin_vec_delete (void *ptr) __attribute__ ((weak, alias ("___builtin_vec_delete")));void___builtin_vec_delete (void *ptr)#elsevoid__builtin_vec_delete (void *ptr)#endif{ __builtin_delete (ptr);}#endif/* End of C++ free-store management functions */#ifdef L_shtabunsigned int __shtab[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000 };#endif#ifdef L_clear_cache/* Clear part of an instruction cache. */#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)void__clear_cache (beg, end) char *beg, *end;{#ifdef CLEAR_INSN_CACHE CLEAR_INSN_CACHE (beg, end);#else#ifdef INSN_CACHE_SIZE static char array[INSN_CACHE_SIZE + INSN_CACHE_PLANE_SIZE + INSN_CACHE_LINE_WIDTH]; static int initialized; int offset; void *start_addr void *end_addr; typedef (*function_ptr) ();#if (INSN_CACHE_SIZE / INSN_CACHE_LINE_WIDTH) < 16 /* It's cheaper to clear the whole cache. Put in a series of jump instructions so that calling the beginning of the cache will clear the whole thing. */ if (! initialized) { int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) & -INSN_CACHE_LINE_WIDTH); int end_ptr = ptr + INSN_CACHE_SIZE; while (ptr < end_ptr) { *(INSTRUCTION_TYPE *)ptr = JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH; ptr += INSN_CACHE_LINE_WIDTH; } *(INSTRUCTION_TYPE *)(ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION; initialized = 1; } /* Call the beginning of the sequence. */ (((function_ptr) (((int) array + INSN_CACHE_LINE_WIDTH - 1) & -INSN_CACHE_LINE_WIDTH)) ());#else /* Cache is large. */ if (! initialized) { int ptr = (((int) array + INSN_CACHE_LINE_WIDTH - 1) & -INSN_CACHE_LINE_WIDTH); while (ptr < (int) array + sizeof array)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -