【C語言學習趣事】_GCC源代碼分析_1_alloca.


  昨天晚上下載了一份GCC V1.42的代碼,不知道是源代碼本身有問題,還是下載的源代碼有問題,看的第一個C文件就存在一些很

奇怪的情況。

  首先要說的是: alloca.c 文件的作用,alloca.c文件的函數實現動態堆空間的分配,即運行時堆棧空間分配。

【1】源代碼

  1 /*
  2     alloca -- (mostly) portable public-domain implementation -- D A Gwyn
  3 
  4     last edit:    86/05/30    rms
  5        include config.h, since on VMS it renames some symbols.
  6        Use xmalloc instead of malloc.
  7 
  8     This implementation of the PWB library alloca() function,
  9     which is used to allocate space off the run-time stack so
 10     that it is automatically reclaimed upon procedure exit, 
 11     was inspired by discussions with J. Q. Johnson of Cornell.
 12 
 13     It should work under any C implementation that uses an
 14     actual procedure stack (as opposed to a linked list of
 15     frames).  There are some preprocessor constants that can
 16     be defined when compiling for your specific system, for
 17     improved efficiency; however, the defaults should be okay.
 18 
 19     The general concept of this implementation is to keep
 20     track of all alloca()-allocated blocks, and reclaim any
 21     that are found to be deeper in the stack than the current
 22     invocation.  This heuristic does not reclaim storage as
 23     soon as it becomes invalid, but it will do so eventually.
 24 
 25     As a special case, alloca(0) reclaims storage without
 26     allocating any.  It is a good idea to use alloca(0) in
 27     your main control loop, etc. to force garbage collection.
 28 */
 29 
 30 
 31 #ifndef lint
 32     static char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
 33 #endif
 34 
 35 #ifdef emacs
 36     #include "config.h"
 37     #ifdef static
 38 /* actually, only want this if static is defined as " "
 39    -- this is for usg, in which emacs must undefine static
 40    in order to make unexec workable
 41    */
 42         #ifndef STACK_DIRECTION
 43             you
 44             lose
 45             -- must know STACK_DIRECTION at compile-time
 46         #endif /* STACK_DIRECTION undefined */
 47     #endif static 
 48 #endif emacs
 49 
 50 
 51 //很顯然這里是對 X3J11 規范的定義
 52 #ifdef X3J11
 53     typedef void    *pointer;        /* generic pointer type */
 54 #else
 55     typedef char    *pointer;        /* generic pointer type */
 56 #endif
 57 
 58 //為什么這個地方不定義為 (void*)
 59 #define    NULL    0            /* null pointer constant */
 60 
 61 extern void    free();
 62 extern pointer    xmalloc();
 63 
 64 /*
 65     Define STACK_DIRECTION if you know the direction of stack
 66     growth for your system; otherwise it will be automatically
 67     deduced at run-time.
 68 
 69     STACK_DIRECTION > 0 => grows toward higher addresses
 70     STACK_DIRECTION < 0 => grows toward lower addresses
 71     STACK_DIRECTION = 0 => direction of growth unknown
 72 */
 73 
 74 
 75 //查看是否定義了棧增長方向宏定義
 76 #ifndef STACK_DIRECTION
 77     #define    STACK_DIRECTION    0        /* direction unknown */
 78 #endif
 79 
 80 //定義棧空間的增長方向宏 STACK_DIR
 81 #if  STACK_DIRECTION != 0
 82     #define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
 83 #else    /* STACK_DIRECTION == 0; need run-time code */
 84     static int    stack_dir;        /* 1 or -1 once known */
 85     #define    STACK_DIR    stack_dir
 86     //下面的函數用來判斷棧的增長方向
 87     static void      
 88     find_stack_direction (/* void */)
 89     {
 90           static char    *addr = NULL;     /* address of first `dummy', once known */
 91           auto char    dummy;        /* to get stack address */
 92 
 93           if (addr == NULL)
 94             {                /* initial entry */
 95               addr = &dummy;
 96                find_stack_direction ();    /* recurse once */
 97          }
 98           else                /* second entry */
 99               if (&dummy > addr)
100                   stack_dir = 1;        /* stack grew upward */
101                else
102                  stack_dir = -1;        /* stack grew downward */
103     }
104 #endif    /* STACK_DIRECTION == 0 */
105 
106 
107 /*
108     An "alloca header" is used to:
109     (a) chain together all alloca()ed blocks;
110     (b) keep track of stack depth.
111 
112     It is very important that sizeof(header) agree with malloc()
113     alignment chunk size.  The following default should work okay.
114 */
115 
116 #ifndef    ALIGN_SIZE
117     #define    ALIGN_SIZE    sizeof(double)
118 #endif 
119 
120 typedef union hdr
121 {
122      char    align[ALIGN_SIZE];    /* to force sizeof(header) */
123      struct
124        {
125            union hdr *next;        /* for chaining headers */
126         char *deep;        /* for stack depth measure */
127      } h;
128 } header;
129 
130 /*
131     alloca( size ) returns a pointer to at least `size' bytes of
132     storage which will be automatically reclaimed upon exit from
133     the procedure that called alloca().  Originally, this space
134     was supposed to be taken from the current stack frame of the
135     caller, but that method cannot be made to work for some
136     implementations of C, for example under Gould's UTX/32.
137 */
138 
139 //全局變量用來存儲 棧 指針
140 static header *last_alloca_header = NULL; /* -> last alloca header */
141 
142 //動態堆分配函數, 這個函數有點類似 malloc 函數
143 //但是這個函數具有垃圾回收機制
144 pointer
145 alloca (size)            /* returns pointer to storage */
146      unsigned    size;        /* # bytes to allocate */
147 {
148   auto char    probe;        /* probes stack depth: */
149   register char    *depth = &probe;
150 
151 #if  STACK_DIRECTION == 0
152       if (STACK_DIR == 0)        /* unknown growth direction */
153             find_stack_direction ();
154 #endif
155 
156 /* Reclaim garbage, defined as all alloca()ed storage that
157 was allocated from deeper in the stack than currently. */
158   {
159     register header    *hp;    /* traverses linked list */
160 
161       //可以發現這里for循環的語法非常特殊
162     for (hp = last_alloca_header; hp != NULL;)
163       if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
164       {
165          register header *np = hp->h.next;
166          free ((pointer) hp);    /* collect garbage */
167          hp = np;        /* -> next header */
168       }
169       else
170         break;            /* rest are not deeper */
171 
172     last_alloca_header = hp;    /* -> last valid storage */
173   }
174 
175   if (size == 0)
176     return NULL;        /* no allocation required */
177 
178   /* Allocate combined header + user data storage. */
179   {
180     register pointer new = xmalloc (sizeof (header) + size);
181     /* address of header */
182 
183     ((header *)new)->h.next = last_alloca_header;
184     ((header *)new)->h.deep = depth;
185 
186     last_alloca_header = (header *)new;
187 
188     /* User storage begins just after header. */
189     return (pointer)((char *)new + sizeof(header));
190    }
191 
192   }
View Code

【2】第一個預處理

#ifndef lint
    static char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
#endif

  這個語句的作用就是定義一個描述源文件作用的數組,同時這個定義在V1.42中是一定定義的;通過代碼分析工具查看交叉索引可以知道:

---- lint Matches (4 in 2 files) ----
Alloca.c (g:\15_gcc\gcc_v1_42\gcc-1.42):#ifndef lint
Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#ifdef lint    /* complains about constant in conditional context */
Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#else        /* !lint */
Va-mips.h (g:\15_gcc\gcc_v1_42\gcc-1.42):#endif        /* lint */

  可以發現在V1.42中並沒有定義這個宏符號:lint

  因此可以確定,SCCSid數組必定定義,而且具有文件內可引用屬性。

【3】第二個預處理

#ifdef emacs
    #include "config.h"
    #ifdef static
/* actually, only want this if static is defined as " "
   -- this is for usg, in which emacs must undefine static
   in order to make unexec workable
   */
        #ifndef STACK_DIRECTION
            you
            lose
            -- must know STACK_DIRECTION at compile-time
        #endif /* STACK_DIRECTION undefined */
    #endif static 
#endif emacs

  同樣,在V1.42中並沒有emacs宏符號的定義,因此這個預處理語句是不會被解釋的

【4】第三個預處理

//很顯然這里是對 X3J11 規范的定義判斷
#ifdef X3J11
    typedef void    *pointer;        /* generic pointer type */
#else
    typedef char    *pointer;        /* generic pointer type */
#endif

  同樣在V1.42中並沒有定義X3J11宏符號,因此 這里定義一個新的數據類型pointer, 其實質數據類型為 char* 

  這里用X3J11表示的是ANSI C標准。

【5】定義宏,和聲明外部符號

//為什么這個地方不定義為 (void*)
#define    NULL    0            /* null pointer constant */

extern void    free();
extern pointer    xmalloc();

  這里,xmalloc 函數相當於malloc函數,用來分配存儲空間

【6】判斷系統棧空間增加方向

//查看是否定義了棧增長方向宏定義
#ifndef STACK_DIRECTION
    #define    STACK_DIRECTION    0        /* direction unknown */
#endif

//定義棧空間的增長方向宏 STACK_DIR
#if  STACK_DIRECTION != 0
    #define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
#else    /* STACK_DIRECTION == 0; need run-time code */
    static int    stack_dir;        /* 1 or -1 once known */
    #define    STACK_DIR    stack_dir
    //下面的函數用來判斷棧的增長方向
    static void      
    find_stack_direction (/* void */)
    {
          static char    *addr = NULL;     /* address of first `dummy', once known */
          auto char    dummy;        /* to get stack address */

          if (addr == NULL)
            {                /* initial entry */
              addr = &dummy;
               find_stack_direction ();    /* recurse once */
         }
          else                /* second entry */
              if (&dummy > addr)
                  stack_dir = 1;        /* stack grew upward */
               else
                 stack_dir = -1;        /* stack grew downward */
    }
#endif    /* STACK_DIRECTION == 0 */

  這里利用一個遞歸函數,find_stack_direction 來判斷棧增長方向,是向高地址方向增長,還是地址方向增長。這里利用了一個static 

local variable  addr 和一個 auto local variable dummy 來判斷增長方向。

  思路比較巧妙。

  static:

    1、global 變量,則將變量作用域限制在單個源文件

    2、函數,則函數不能被定義函數源文件外的函數調用

    3、local 變量, 延長變量生命周期

【7】堆 空間指針類型

#ifndef    ALIGN_SIZE
    #define    ALIGN_SIZE    sizeof(double)
#endif 

typedef union hdr
{
     char    align[ALIGN_SIZE];    /* to force sizeof(header) */
     struct
       {
           union hdr *next;        /* for chaining headers */
          char *deep;        /* for stack depth measure */
     } h;
} header;

  定義了數據類型 header ,並且是用遞歸的聯合體定義的, 聯合體中定義成語域 align的目的是為了數據對齊;在下面的源代碼中並沒有

對這個成員域的引用

【8】堆 空間指針變量

//全局變量用來存儲 棧 指針
static header *last_alloca_header = NULL; /* -> last alloca header */

  這里注釋: last_alloca_header 用來指向最新分配的空間頭(基指針)

【9】alloca函數

 1 //動態堆分配函數, 這個函數有點類似 malloc 函數
 2 //但是這個函數具有垃圾回收機制
 3 pointer
 4 alloca (size)            /* returns pointer to storage */
 5      unsigned    size;        /* # bytes to allocate */
 6 {
 7   auto char    probe;        /* probes stack depth: */
 8   register char    *depth = &probe;
 9 
10 #if  STACK_DIRECTION == 0
11       if (STACK_DIR == 0)        /* unknown growth direction */
12             find_stack_direction ();
13 #endif
14 
15 /* Reclaim garbage, defined as all alloca()ed storage that
16 was allocated from deeper in the stack than currently. */
17   {
18     register header    *hp;    /* traverses linked list */
19 
20       //可以發現這里for循環的語法非常特殊
21     for (hp = last_alloca_header; hp != NULL;)
22       if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
23       {
24          register header *np = hp->h.next;
25          free ((pointer) hp);    /* collect garbage */
26          hp = np;        /* -> next header */
27       }
28       else
29         break;            /* rest are not deeper */
30 
31     last_alloca_header = hp;    /* -> last valid storage */
32   }
33 
34   if (size == 0)
35     return NULL;        /* no allocation required */
36 
37   /* Allocate combined header + user data storage. */
38   {
39     register pointer new = xmalloc (sizeof (header) + size);
40     /* address of header */
41 
42     ((header *)new)->h.next = last_alloca_header;
43     ((header *)new)->h.deep = depth;
44 
45     last_alloca_header = (header *)new;
46 
47     /* User storage begins just after header. */
48     return (pointer)((char *)new + sizeof(header));
49    }
50 
51   }
View Code

函數原型:

pointer
alloca (size)            /* returns pointer to storage */
     unsigned    size;    

  可以發現這里采用的老式的C語言函數定義形式,或者函數原型聲明形式。

局部變量:

auto char    probe;        /* probes stack depth: */
register char    *depth = &probe;

  局部變量用來檢測堆棧的深度,

  register:

      1、聲明為register的變量,表示要存儲在CPU的寄存器中,提高存儲效率。

判斷堆棧增長方向:

#if  STACK_DIRECTION == 0
      if (STACK_DIR == 0)        /* unknown growth direction */
            find_stack_direction ();
#endif

  增長結果存儲在stack_dir全局變量中。

回收內存:

/* Reclaim garbage, defined as all alloca()ed storage that
was allocated from deeper in the stack than currently. */
  {
    register header    *hp;    /* traverses linked list */

      //可以發現這里for循環的語法非常特殊
    for (hp = last_alloca_header; hp != NULL;)
      if (STACK_DIR > 0 && hp->h.deep > depth || STACK_DIR < 0 && hp->h.deep < depth)
      {
         register header *np = hp->h.next;
         free ((pointer) hp);    /* collect garbage */
         hp = np;        /* -> next header */
      }
      else
        break;            /* rest are not deeper */

    last_alloca_header = hp;    /* -> last valid storage */
  }

 分配空間

      如果申請的空間為0,則返回空指針。

if (size == 0)
    return NULL;        /* no allocation required */

  如果申請的空間不為0 ,則返回申請空間的地址

 /* Allocate combined header + user data storage. */
  {
    register pointer new = xmalloc (sizeof (header) + size);
    /* address of header */

    ((header *)new)->h.next = last_alloca_header;
    ((header *)new)->h.deep = depth;

    last_alloca_header = (header *)new;

    /* User storage begins just after header. */
    return (pointer)((char *)new + sizeof(header));
   }

  }

調用的主要函數:xmalloc的定義如下

int
xmalloc (size)
{
  register int val = malloc (size);

  if (val == 0)
    fatal ("virtual memory exhausted");
  return val;
}

  可以發現,這個函數還是調用的庫函數malloc來實現的,但是這個函數有一個特點,其返回值是一個int類型的值,也就是說這個函數

返回的可能是一個負值。

 

  反正我下載的這個代碼庫的源代碼感覺是不對的,但是這里面一些思想和內容大體是對的,因此可以學習。 

下面是我看到的bash 4.0 中關於這個函數alloca的源代碼:

/** alloca.c -- allocate automatically reclaimed memory
   (Mostly) portable public-domain implementation -- D A Gwyn

   This implementation of the PWB library alloca function,
   which is used to allocate space off the run-time stack so
   that it is automatically reclaimed upon procedure exit,
   was inspired by discussions with J. Q. Johnson of Cornell.
   J.Otto Tennant <jot@cray.com> contributed the Cray support.

   There are some preprocessor constants that can
   be defined when compiling for your specific system, for
   improved efficiency; however, the defaults should be okay.

   The general concept of this implementation is to keep
   track of all alloca-allocated blocks, and reclaim any
   that are found to be deeper in the stack than the current
   invocation.  This heuristic does not reclaim storage as
   soon as it becomes invalid, but it will do so eventually.

   As a special case, alloca(0) reclaims storage without
   allocating any.  It is a good idea to use alloca(0) in
   your main control loop, etc. to force garbage collection.  */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/** If compiling with GCC 2, this file's not needed.  */
#if !defined (__GNUC__) || __GNUC__ < 2

#include <bashtypes.h>        /** for size_t */

/** If alloca is defined somewhere, this file is not needed. */
#ifndef alloca

#ifdef emacs
#ifdef static
/** actually, only want this if static is defined as ""
   -- this is for usg, in which emacs must undefine static
   in order to make unexec workable
   */
#ifndef STACK_DIRECTION
you
lose
-- must know STACK_DIRECTION at compile-time
#endif /** STACK_DIRECTION undefined */
#endif /** static */
#endif /** emacs */

/** If your stack is a linked list of frames, you have to
   provide an "address metric" ADDRESS_FUNCTION macro.  */

#if defined (CRAY) && defined (CRAY_STACKSEG_END)
long i00afunc ();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif /** CRAY && CRAY_STACKSEG_END */

#if __STDC__
typedef void *pointer;
#else
typedef char *pointer;
#endif

#define    NULL    0

/** Different portions of Emacs need to call different versions of
   malloc.  The Emacs executable needs alloca to call xmalloc, because
   ordinary malloc isn't protected from input signals.  On the other
   hand, the utilities in lib-src need alloca to call malloc; some of
   them are very simple, and don't have an xmalloc routine.

   Non-Emacs programs expect this to call use xmalloc.

   Callers below should use malloc.  */

#ifndef emacs
#define malloc xmalloc
extern pointer xmalloc ();
#endif

/** Define STACK_DIRECTION if you know the direction of stack
   growth for your system; otherwise it will be automatically
   deduced at run-time.

   STACK_DIRECTION > 0 => grows toward higher addresses
   STACK_DIRECTION < 0 => grows toward lower addresses
   STACK_DIRECTION = 0 => direction of growth unknown  */

#ifndef STACK_DIRECTION
#define    STACK_DIRECTION    0    /** Direction unknown.  */
#endif

#if STACK_DIRECTION != 0

#define    STACK_DIR    STACK_DIRECTION    /** Known at compile-time.  */

#else /** STACK_DIRECTION == 0; need run-time code.  */

static int stack_dir;        /** 1 or -1 once known.  */
#define    STACK_DIR    stack_dir

static void
find_stack_direction ()
{
  static char *addr = NULL;    /** Address of first `dummy', once known.  */
  auto char dummy;        /** To get stack address.  */

  if (addr == NULL)
    {                /** Initial entry.  */
      addr = ADDRESS_FUNCTION (dummy);

      find_stack_direction ();    /** Recurse once.  */
    }
  else
    {
      /** Second entry.  */
      if (ADDRESS_FUNCTION (dummy) > addr)
    stack_dir = 1;        /** Stack grew upward.  */
      else
    stack_dir = -1;        /** Stack grew downward.  */
    }
}

#endif /** STACK_DIRECTION == 0 */

/** An "alloca header" is used to:
   (a) chain together all alloca'ed blocks;
   (b) keep track of stack depth.

   It is very important that sizeof(header) agree with malloc
   alignment chunk size.  The following default should work okay.  */

#ifndef    ALIGN_SIZE
#define    ALIGN_SIZE    sizeof(double)
#endif

typedef union hdr
{
  char align[ALIGN_SIZE];    /** To force sizeof(header).  */
  struct
    {
      union hdr *next;        /** For chaining headers.  */
      char *deep;        /** For stack depth measure.  */
    } h;
} header;

static header *last_alloca_header = NULL;    /** -> last alloca header.  */

/** Return a pointer to at least SIZE bytes of storage,
   which will be automatically reclaimed upon exit from
   the procedure that called alloca.  Originally, this space
   was supposed to be taken from the current stack frame of the
   caller, but that method cannot be made to work for some
   implementations of C, for example under Gould's UTX/32.  */

pointer
alloca (size)
     size_t size;
{
  auto char probe;        /** Probes stack depth: */
  register char *depth = ADDRESS_FUNCTION (probe);

#if STACK_DIRECTION == 0
  if (STACK_DIR == 0)        /** Unknown growth direction.  */
    find_stack_direction ();
#endif

  /** Reclaim garbage, defined as all alloca'd storage that
     was allocated from deeper in the stack than currently. */

  {
    register header *hp;    /** Traverses linked list.  */

    for (hp = last_alloca_header; hp != NULL;)
      if ((STACK_DIR > 0 && hp->h.deep > depth)
      || (STACK_DIR < 0 && hp->h.deep < depth))
    {
      register header *np = hp->h.next;

      free ((pointer) hp);    /** Collect garbage.  */

      hp = np;        /** -> next header.  */
    }
      else
    break;            /** Rest are not deeper.  */

    last_alloca_header = hp;    /** -> last valid storage.  */
  }

  if (size == 0)
    return NULL;        /** No allocation required.  */

  /** Allocate combined header + user data storage.  */

  {
    register pointer new = malloc (sizeof (header) + size);
    /** Address of header.  */

    ((header *) new)->h.next = last_alloca_header;
    ((header *) new)->h.deep = depth;

    last_alloca_header = (header *) new;

    /** User storage begins just after header.  */

    return (pointer) ((char *) new + sizeof (header));
  }
}

#if defined (CRAY) && defined (CRAY_STACKSEG_END)

#ifdef DEBUG_I00AFUNC
#include <stdio.h>
#endif

#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/** Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header
  {
    long shgrow:32;        /** Number of times stack has grown.  */
    long shaseg:32;        /** Size of increments to stack.  */
    long shhwm:32;        /** High water mark of stack.  */
    long shsize:32;        /** Current size of stack (all segments).  */
  };

/** The stack segment linkage control information occurs at
   the high-address end of a stack segment.  (The stack
   grows from low addresses to high addresses.)  The initial
   part of the stack segment linkage control information is
   0200 (octal) words.  This provides for register storage
   for the routine which overflows the stack.  */

struct stack_segment_linkage
  {
    long ss[0200];        /** 0200 overflow words.  */
    long sssize:32;        /** Number of words in this segment.  */
    long ssbase:32;        /** Offset to stack base.  */
    long:32;
    long sspseg:32;        /** Offset to linkage control of previous
                   segment of stack.  */
    long:32;
    long sstcpt:32;        /** Pointer to task common address block.  */
    long sscsnm;        /** Private control structure number for
                   microtasking.  */
    long ssusr1;        /** Reserved for user.  */
    long ssusr2;        /** Reserved for user.  */
    long sstpid;        /** Process ID for pid based multi-tasking.  */
    long ssgvup;        /** Pointer to multitasking thread giveup.  */
    long sscray[7];        /** Reserved for Cray Research.  */
    long ssa0;
    long ssa1;
    long ssa2;
    long ssa3;
    long ssa4;
    long ssa5;
    long ssa6;
    long ssa7;
    long sss0;
    long sss1;
    long sss2;
    long sss3;
    long sss4;
    long sss5;
    long sss6;
    long sss7;
  };

#else /** CRAY2 */
/** The following structure defines the vector of words
   returned by the STKSTAT library routine.  */
struct stk_stat
  {
    long now;            /** Current total stack size.  */
    long maxc;            /** Amount of contiguous space which would
                   be required to satisfy the maximum
                   stack demand to date.  */
    long high_water;        /** Stack high-water mark.  */
    long overflows;        /** Number of stack overflow ($STKOFEN) calls.  */
    long hits;            /** Number of internal buffer hits.  */
    long extends;        /** Number of block extensions.  */
    long stko_mallocs;        /** Block allocations by $STKOFEN.  */
    long underflows;        /** Number of stack underflow calls ($STKRETN).  */
    long stko_free;        /** Number of deallocations by $STKRETN.  */
    long stkm_free;        /** Number of deallocations by $STKMRET.  */
    long segments;        /** Current number of stack segments.  */
    long maxs;            /** Maximum number of stack segments so far.  */
    long pad_size;        /** Stack pad size.  */
    long current_address;    /** Current stack segment address.  */
    long current_size;        /** Current stack segment size.  This
                   number is actually corrupted by STKSTAT to
                   include the fifteen word trailer area.  */
    long initial_address;    /** Address of initial segment.  */
    long initial_size;        /** Size of initial segment.  */
  };

/** The following structure describes the data structure which trails
   any stack segment.  I think that the description in 'asdef' is
   out of date.  I only describe the parts that I am sure about.  */

struct stk_trailer
  {
    long this_address;        /** Address of this block.  */
    long this_size;        /** Size of this block (does not include
                   this trailer).  */
    long unknown2;
    long unknown3;
    long link;            /** Address of trailer block of previous
                   segment.  */
    long unknown5;
    long unknown6;
    long unknown7;
    long unknown8;
    long unknown9;
    long unknown10;
    long unknown11;
    long unknown12;
    long unknown13;
    long unknown14;
  };

#endif /** CRAY2 */
#endif /** not CRAY_STACK */

#ifdef CRAY2
/** Determine a "stack measure" for an arbitrary ADDRESS.
   I doubt that "lint" will like this much. */

static long
i00afunc (long *address)
{
  struct stk_stat status;
  struct stk_trailer *trailer;
  long *block, size;
  long result = 0;

  /** We want to iterate through all of the segments.  The first
     step is to get the stack status structure.  We could do this
     more quickly and more directly, perhaps, by referencing the
     $LM00 common block, but I know that this works.  */

  STKSTAT (&status);

  /** Set up the iteration.  */

  trailer = (struct stk_trailer *) (status.current_address
                    + status.current_size
                    - 15);

  /** There must be at least one stack segment.  Therefore it is
     a fatal error if "trailer" is null.  */

  if (trailer == 0)
    abort ();

  /** Discard segments that do not contain our argument address.  */

  while (trailer != 0)
    {
      block = (long *) trailer->this_address;
      size = trailer->this_size;
      if (block == 0 || size == 0)
    abort ();
      trailer = (struct stk_trailer *) trailer->link;
      if ((block <= address) && (address < (block + size)))
    break;
    }

  /** Set the result to the offset in this segment and add the sizes
     of all predecessor segments.  */

  result = address - block;

  if (trailer == 0)
    {
      return result;
    }

  do
    {
      if (trailer->this_size <= 0)
    abort ();
      result += trailer->this_size;
      trailer = (struct stk_trailer *) trailer->link;
    }
  while (trailer != 0);

  /** We are done.  Note that if you present a bogus address (one
     not in any segment), you will get a different number back, formed
     from subtracting the address of the first block.  This is probably
     not what you want.  */

  return (result);
}

#else /** not CRAY2 */
/** Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
   Determine the number of the cell within the stack,
   given the address of the cell.  The purpose of this
   routine is to linearize, in some sense, stack addresses
   for alloca.  */

static long
i00afunc (long address)
{
  long stkl = 0;

  long size, pseg, this_segment, stack;
  long result = 0;

  struct stack_segment_linkage *ssptr;

  /** Register B67 contains the address of the end of the
     current stack segment.  If you (as a subprogram) store
     your registers on the stack and find that you are past
     the contents of B67, you have overflowed the segment.

     B67 also points to the stack segment linkage control
     area, which is what we are really interested in.  */

  /** This might be _getb67() or GETB67 () or getb67 () */
  stkl = CRAY_STACKSEG_END ();
  ssptr = (struct stack_segment_linkage *) stkl;

  /** If one subtracts 'size' from the end of the segment,
     one has the address of the first word of the segment.

     If this is not the first segment, 'pseg' will be
     nonzero.  */

  pseg = ssptr->sspseg;
  size = ssptr->sssize;

  this_segment = stkl - size;

  /** It is possible that calling this routine itself caused
     a stack overflow.  Discard stack segments which do not
     contain the target address.  */

  while (!(this_segment <= address && address <= stkl))
    {
#ifdef DEBUG_I00AFUNC
      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
#endif
      if (pseg == 0)
    break;
      stkl = stkl - pseg;
      ssptr = (struct stack_segment_linkage *) stkl;
      size = ssptr->sssize;
      pseg = ssptr->sspseg;
      this_segment = stkl - size;
    }

  result = address - this_segment;

  /** If you subtract pseg from the current end of the stack,
     you get the address of the previous stack segment's end.
     This seems a little convoluted to me, but I'll bet you save
     a cycle somewhere.  */

  while (pseg != 0)
    {
#ifdef DEBUG_I00AFUNC
      fprintf (stderr, "%011o %011o\n", pseg, size);
#endif
      stkl = stkl - pseg;
      ssptr = (struct stack_segment_linkage *) stkl;
      size = ssptr->sssize;
      pseg = ssptr->sspseg;
      result += size;
    }
  return (result);
}

#endif /** not CRAY2 */
#endif /** CRAY && CRAY_STACKSEG_END */

#endif /** no alloca */
#endif /** !__GNUC__ || __GNUC__ < 2 */
View Code

  可以發現兩個的寫法還是有很多的區別。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM