/[gcl]/gcl/o/sfaslpecoff.c
ViewVC logotype

Diff of /gcl/o/sfaslpecoff.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by mjthomas, Sat Sep 18 01:58:09 2004 UTC revision 1.5 by mjthomas, Wed Sep 22 02:33:21 2004 UTC
# Line 35  int debug; Line 35  int debug;
35  #endif  #endif
36  #define PTABLE_EXTRA 20  #define PTABLE_EXTRA 20
37    
38  #define COFF_SECTIONS 10   /* Numbner of section headers in section header buffer */  #define COFF_SECTIONS 10 /* Numbner of section headers in section header buffer */
39    
40  #define INVALID_NSCN 64000   /* A number greater than the number of sections ever likely to be read in. */  #define INVALID_NSCN 64000 /* A number greater than the number of sections ever likely to be read in. */
41    
42  #define SYMNMLEN 8  #define SYMNMLEN 8
43  #define SYM_NAME(p) \  #define SYM_NAME(p) \
44    (((p)->N.Name.Short == 0) ? \      (((p)->N.Name.Short == 0) ? \
45              &my_string_table[(p)->N.Name.Long] : \        &my_string_table[(p)->N.Name.Long] : \
46                 ((p)->N.ShortName[7] ? \        ((p)->N.ShortName[7] ? \
47                                   ( strncpy ( tem, (p)->N.ShortName,  \          ( strncpy ( tem, (p)->N.ShortName,  \
48                                             8 ), \                      8 ), \
49                                    (char *) tem) : \            (char *) tem) : \
50                                    (p)->N.ShortName ))          (p)->N.ShortName ))
51    
52  /*  /*
53   * names of "special" sections   * names of "special" sections
# Line 62  int debug; Line 62  int debug;
62  #define _LIB        ".lib"  #define _LIB        ".lib"
63    
64  unsigned int TEXT_NSCN = INVALID_NSCN, DATA_NSCN = INVALID_NSCN,  unsigned int TEXT_NSCN = INVALID_NSCN, DATA_NSCN = INVALID_NSCN,
65    BSS_NSCN = INVALID_NSCN, STAB_NSCN = INVALID_NSCN,      BSS_NSCN = INVALID_NSCN, STAB_NSCN = INVALID_NSCN,
66    STABSTR_NSCN = INVALID_NSCN, RDATA_NSCN = INVALID_NSCN,      STABSTR_NSCN = INVALID_NSCN, RDATA_NSCN = INVALID_NSCN,
67    BIGGEST_NSCN_FOUND = 0;      BIGGEST_NSCN_FOUND = 0;
68    
69  struct sfasl_info {  struct sfasl_info {
70      PIMAGE_SYMBOL s_symbol_table;      PIMAGE_SYMBOL s_symbol_table;
# Line 142  void describe_sym1 ( int n, int aux_to_g Line 142  void describe_sym1 ( int n, int aux_to_g
142    
143  /* This function does the low level relocation. */  /* This function does the low level relocation. */
144  void  void
145  relocate()      relocate()
146  {  {
147    char *where;      char *where;
148    /* describe_sym ( relocation_info.r_symndx, 0 ); */      /* describe_sym ( relocation_info.r_symndx, 0 ); */
149    where = the_start + relocation_info.VirtualAddress;      where = the_start + relocation_info.VirtualAddress;
150    if ( relocation_info.Type == IMAGE_REL_I386_ABSOLUTE ) {      if ( relocation_info.Type == IMAGE_REL_I386_ABSOLUTE ) {
151      return;          return;
   }  
     
   switch(relocation_info.Type)  
     {  
   
     case IMAGE_REL_I386_DIR32:  
       *(int *)where = *((int *)where) +  
         symbol_table[relocation_info.SymbolTableIndex].Value;  
       break;  
         
     case IMAGE_REL_I386_REL32:  
       /* the following is logical, except the address offset is  
          not where the 'where' is but where the 'call' is just  
          AFTER the 'where'.  
       */  
       *(int *)where = symbol_table[relocation_info.SymbolTableIndex].Value  
         - (int) where - sizeof(int *);  
   
       break;  
   
     default:  
       fprintf ( stderr, "%d: unsupported relocation type.\n",  
                 relocation_info.Type);  
       FEerror("The relocation type was unknown\n",0,0);  
152      }      }
153        
154        switch(relocation_info.Type)
155            {
156    
157            case IMAGE_REL_I386_DIR32:
158                *(int *)where = *((int *)where) +
159                    symbol_table[relocation_info.SymbolTableIndex].Value;
160                break;
161                
162            case IMAGE_REL_I386_REL32:
163                /* the following is logical, except the address offset is
164                   not where the 'where' is but where the 'call' is just
165                   AFTER the 'where'.
166                   */
167                *(int *)where = symbol_table[relocation_info.SymbolTableIndex].Value
168                    - (int) where - sizeof(int *);
169    
170                break;
171    
172            default:
173                fprintf ( stderr, "%d: unsupported relocation type.\n",
174                          relocation_info.Type);
175                FEerror("The relocation type was unknown\n",0,0);
176            }
177    
178  }  }
179    
# Line 190  void set_symbol_address ( PIMAGE_SYMBOL Line 190  void set_symbol_address ( PIMAGE_SYMBOL
190   */   */
191  static void work_out_section_indices ( IMAGE_SECTION_HEADER *section )  static void work_out_section_indices ( IMAGE_SECTION_HEADER *section )
192  {  {
193    unsigned int i;      unsigned int i;
194    
195    /* Initialise the global *_NSCN variables to INVALID_NSCN */      /* Initialise the global *_NSCN variables to INVALID_NSCN */
196    TEXT_NSCN = DATA_NSCN = BSS_NSCN = STAB_NSCN = STABSTR_NSCN = RDATA_NSCN = INVALID_NSCN;      TEXT_NSCN = DATA_NSCN = BSS_NSCN = STAB_NSCN = STABSTR_NSCN = RDATA_NSCN = INVALID_NSCN;
197          
198    for ( i = 1; i < COFF_SECTIONS; i++ ) {      for ( i = 1; i < COFF_SECTIONS; i++ ) {
199      if ( strcmp(section[i].Name, _TEXT) == 0 ) {          if ( strcmp(section[i].Name, _TEXT) == 0 ) {
200        TEXT_NSCN = i;              TEXT_NSCN = i;
201        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
202      }          }
203      if ( strcmp(section[i].Name, _DATA) == 0 ) {          if ( strcmp(section[i].Name, _DATA) == 0 ) {
204        DATA_NSCN = i;              DATA_NSCN = i;
205        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
206      }          }
207      if ( strcmp(section[i].Name, _BSS ) == 0 ) {          if ( strcmp(section[i].Name, _BSS ) == 0 ) {
208        BSS_NSCN = i;              BSS_NSCN = i;
209        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
210      }          }
211      if ( strcmp(section[i].Name, _STAB ) == 0 ) {          if ( strcmp(section[i].Name, _STAB ) == 0 ) {
212        STAB_NSCN = i;              STAB_NSCN = i;
213        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
214      }          }
215      if ( strcmp(section[i].Name, _STABSTR) == 0 ) {          if ( strcmp(section[i].Name, _STABSTR) == 0 ) {
216        STABSTR_NSCN = i;              STABSTR_NSCN = i;
217        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
218      }          }
219      if ( strcmp(section[i].Name, _RDATA) == 0 ) {          if ( strcmp(section[i].Name, _RDATA) == 0 ) {
220        RDATA_NSCN = i;              RDATA_NSCN = i;
221        if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;              if ( i > BIGGEST_NSCN_FOUND ) BIGGEST_NSCN_FOUND = i;
222            }
223      }      }
   }  
224  }  }
225    
226  int fasload ( object faslfile )  int fasload ( object faslfile )
# Line 231  int fasload ( object faslfile ) Line 231  int fasload ( object faslfile )
231      IMAGE_SECTION_HEADER section[COFF_SECTIONS];      IMAGE_SECTION_HEADER section[COFF_SECTIONS];
232      IMAGE_OPTIONAL_HEADER optional_header;      IMAGE_OPTIONAL_HEADER optional_header;
233      int textsize = 0, datasize = 0, bsssize = 0, stabsize = 0,      int textsize = 0, datasize = 0, bsssize = 0, stabsize = 0,
234        stabstrsize = 0, rdatasize = 0, nsyms = 0;      stabstrsize = 0, rdatasize = 0, nsyms = 0;
235      object memory, data;      object memory, data;
236      FILE *fp;      FILE *fp;
237      char filename[MAXPATHLEN];      char filename[MAXPATHLEN];
# Line 283  int fasload ( object faslfile ) Line 283  int fasload ( object faslfile )
283    
284      /* Check for text section that does not come first - not currently handled. */      /* Check for text section that does not come first - not currently handled. */
285      if ( ( INVALID_NSCN != TEXT_NSCN ) && ( TEXT_NSCN != 1 ) ) {      if ( ( INVALID_NSCN != TEXT_NSCN ) && ( TEXT_NSCN != 1 ) ) {
286        FEerror ("Can't handle a Text section at other than index 1.",0);          FEerror ("Can't handle a Text section at other than index 1.",0);
287      }      }
288    
289      /* Determine the section sizes used later to allocate storage and to calculate      /* Determine the section sizes used later to allocate storage and to calculate
290       * the offsets of the sections once read in. Allow for the possibility       * the offsets of the sections once read in. Allow for the possibility
291       * of an invalid index, that is, that a section may not be present. */       * of an invalid index, that is, that a section may not be present. */
292      if ( INVALID_NSCN != TEXT_NSCN ) {      if ( INVALID_NSCN != TEXT_NSCN ) {
293        textsize = section[TEXT_NSCN].SizeOfRawData;          textsize = section[TEXT_NSCN].SizeOfRawData;
294      }      }
295      if ( INVALID_NSCN != DATA_NSCN ) {      if ( INVALID_NSCN != DATA_NSCN ) {
296        datasize = section[DATA_NSCN].SizeOfRawData;          datasize = section[DATA_NSCN].SizeOfRawData;
297      }      }
298      if ( INVALID_NSCN != BSS_NSCN ) {      if ( INVALID_NSCN != BSS_NSCN ) {
299        bsssize = section[BSS_NSCN].SizeOfRawData;          bsssize = section[BSS_NSCN].SizeOfRawData;
300      }      }
301      if ( INVALID_NSCN != STAB_NSCN ) {      if ( INVALID_NSCN != STAB_NSCN ) {
302        stabsize = section[STAB_NSCN].SizeOfRawData;          stabsize = section[STAB_NSCN].SizeOfRawData;
303      }      }
304      if ( INVALID_NSCN != STABSTR_NSCN ) {      if ( INVALID_NSCN != STABSTR_NSCN ) {
305        stabstrsize = section[STABSTR_NSCN].SizeOfRawData;          stabstrsize = section[STABSTR_NSCN].SizeOfRawData;
306      }      }
307      if ( INVALID_NSCN != RDATA_NSCN ) {      if ( INVALID_NSCN != RDATA_NSCN ) {
308        rdatasize = section[RDATA_NSCN].SizeOfRawData;          rdatasize = section[RDATA_NSCN].SizeOfRawData;
309      }      }
310    
311      /* Allocate space for the symbol table */      /* Allocate space for the symbol table */
312      symbol_table =      symbol_table =
313          (PIMAGE_SYMBOL) OUR_ALLOCA ( sizeof ( IMAGE_SYMBOL ) *          (PIMAGE_SYMBOL) OUR_ALLOCA ( sizeof ( IMAGE_SYMBOL ) *
314                                        (unsigned int) nsyms );                                       (unsigned int) nsyms );
315      memset ( symbol_table, 0, sizeof ( IMAGE_SYMBOL ) * (unsigned int) nsyms );      memset ( symbol_table, 0, sizeof ( IMAGE_SYMBOL ) * (unsigned int) nsyms );
316      /* move the file pointer to the start of the symbol table */      /* move the file pointer to the start of the symbol table */
317      fseek ( fp, (int) fileheader.PointerToSymbolTable,  0 );      fseek ( fp, (int) fileheader.PointerToSymbolTable,  0 );
# Line 344  int fasload ( object faslfile ) Line 344  int fasload ( object faslfile )
344          /* Go to the end of the C compiler generated object data          /* Go to the end of the C compiler generated object data
345             in preparation for loading the GCL fasl data. */             in preparation for loading the GCL fasl data. */
346          {          {
347            struct filehdr fileheader;              struct filehdr fileheader;
348            int i;              int i;
349            fseek ( fp, 0, 0 );              fseek ( fp, 0, 0 );
350            fread ( &fileheader, sizeof ( fileheader ), 1, fp );              fread ( &fileheader, sizeof ( fileheader ), 1, fp );
351            fseek ( fp, fileheader.f_symptr + fileheader.f_nsyms * SYMESZ, 0 );              fseek ( fp, fileheader.f_symptr + fileheader.f_nsyms * SYMESZ, 0 );
352            fread ( &i, sizeof ( i ), 1, fp );              fread ( &i, sizeof ( i ), 1, fp );
353            fseek ( fp, i - sizeof ( i ), 1 );              fseek ( fp, i - sizeof ( i ), 1 );
354            while ( ( i = fgetc ( fp ) ) == 0 );              while ( ( i = fgetc ( fp ) ) == 0 );
355            ungetc ( i, fp );              ungetc ( i, fp );
356          }          }
357    
358  #endif  #endif
# Line 366  int fasload ( object faslfile ) Line 366  int fasload ( object faslfile )
366    
367          /* figure out if there is more bss space needed */          /* figure out if there is more bss space needed */
368          extra_bss =          extra_bss =
369            get_extra_bss ( symbol_table,              get_extra_bss ( symbol_table,
370                            nsyms,                              nsyms,
371                            datasize + textsize + bsssize +                              datasize + textsize + bsssize +
372                            stabsize + stabstrsize + rdatasize,                              stabsize + stabstrsize + rdatasize,
373                            &init_address,                              &init_address,
374                            bsssize );                              bsssize );
375                    
376          /* allocate some memory */          /* allocate some memory */
377          {          {
# Line 380  int fasload ( object faslfile ) Line 380  int fasload ( object faslfile )
380              memory->cfd.cfd_self = 0;              memory->cfd.cfd_self = 0;
381              memory->cfd.cfd_start = 0;              memory->cfd.cfd_start = 0;
382              memory->cfd.cfd_size =              memory->cfd.cfd_size =
383                datasize + textsize + bsssize +                  datasize + textsize + bsssize +
384                stabsize + stabstrsize + rdatasize + extra_bss;                      stabsize + stabstrsize + rdatasize + extra_bss;
385              vs_push(memory);              vs_push(memory);
386              the_start = start_address =                      the_start = start_address =        
387                  memory->cfd.cfd_start =                  memory->cfd.cfd_start =
388                      alloc_contblock ( memory->cfd.cfd_size );                      alloc_contblock ( memory->cfd.cfd_size );
389              sfaslp->s_start_data  = start_address + textsize;              sfaslp->s_start_data  = start_address + textsize;
390              sfaslp->s_start_rdata = sfaslp->s_start_data + datasize              sfaslp->s_start_rdata = sfaslp->s_start_data + datasize
391                + stabsize + stabstrsize;                  + stabsize + stabstrsize;
392              sfaslp->s_start_bss   = sfaslp->s_start_rdata + rdatasize;              sfaslp->s_start_bss   = sfaslp->s_start_rdata + rdatasize;
393              END_NO_INTERRUPT;              END_NO_INTERRUPT;
394          }          }
# Line 412  int fasload ( object faslfile ) Line 412  int fasload ( object faslfile )
412                       ( 0 != section[j].NumberOfRelocations ) ) {                       ( 0 != section[j].NumberOfRelocations ) ) {
413                      fseek ( fp, section[j].PointerToRelocations, 0 );                      fseek ( fp, section[j].PointerToRelocations, 0 );
414                      if ( j == TEXT_NSCN ) {                      if ( j == TEXT_NSCN ) {
415                        the_start = memory->cfd.cfd_start;                          the_start = memory->cfd.cfd_start;
416                      } else {                      } else {
417                        if ( j == DATA_NSCN ) {                          if ( j == DATA_NSCN ) {
418                          the_start = sfaslp->s_start_data;                              the_start = sfaslp->s_start_data;
419                        } else {                          } else {
420                          if ( j == RDATA_NSCN ) {                              if ( j == RDATA_NSCN ) {
421                            the_start = sfaslp->s_start_rdata;                                  the_start = sfaslp->s_start_rdata;
422                          } else {                              } else {
423                            the_start = 0;                                  the_start = 0;
424                            FEerror ( "The_start was set to 0.\n", 0 );                                  FEerror ( "The_start was set to 0.\n", 0 );
425                          }                              }
426                        }                          }
427                      }                      }
428                      for ( i=0; i < section[j].NumberOfRelocations; i++ ) {                      for ( i=0; i < section[j].NumberOfRelocations; i++ ) {
429                          fread ( &relocation_info, sizeof (IMAGE_RELOCATION), 1, fp );                          fread ( &relocation_info, sizeof (IMAGE_RELOCATION), 1, fp );
# Line 456  int fasload ( object faslfile ) Line 456  int fasload ( object faslfile )
456  }  }
457    
458  int get_extra_bss(sym_table,length,start,ptr,bsssize)  int get_extra_bss(sym_table,length,start,ptr,bsssize)
459       int length,bsssize;      int length,bsssize;
460       PIMAGE_SYMBOL sym_table;      PIMAGE_SYMBOL sym_table;
461       int *ptr;                   /* store init address offset here */      int *ptr;                   /* store init address offset here */
462  {  {
463    int result = start;      int result = start;
464    IMAGE_SYMBOL *end, *sym;      IMAGE_SYMBOL *end, *sym;
465    
466    end =sym_table + length;      end =sym_table + length;
467    
468    for ( sym = sym_table; sym < end; sym++ ) {      for ( sym = sym_table; sym < end; sym++ ) {
469      /* The C compiler optimiser sometimes moves object initialisation          /* The C compiler optimiser sometimes moves object initialisation
470         code around. */             code around. */
471      if ( ( *ptr == 0 ) && ( sym->SectionNumber == TEXT_NSCN ) && sym->Value ) {          if ( ( *ptr == 0 ) && ( sym->SectionNumber == TEXT_NSCN ) && sym->Value ) {
472        char tem [9];              char tem [9];
473        char *str = SYM_NAME ( sym );              char *str = SYM_NAME ( sym );
474        if ( str[1] == 'i' && str[2] == 'n' && str[3] == 'i' &&              if ( str[1] == 'i' && str[2] == 'n' && str[3] == 'i' &&
475             str[4] == 't' && str[5] == '_' && str[0] == '_' ) {                   str[4] == 't' && str[5] == '_' && str[0] == '_' ) {
476          *ptr=  sym->Value ;                  *ptr=  sym->Value ;
477        }              }
478      }          }
479      if(0)          if(0)
480        /* what we really want is              /* what we really want is
481           if (sym->n_scnum==0 && sym->n_sclass == C_EXT                 if (sym->n_scnum==0 && sym->n_sclass == C_EXT
482           && !(bsearch(..in ptable for this symbol)))                 && !(bsearch(..in ptable for this symbol)))
483           Since this won't allow loading in of a new external array                 Since this won't allow loading in of a new external array
484           char foo[10]  not ok                 char foo[10]  not ok
485           static foo[10] ok.                 static foo[10] ok.
486           for the moment we give undefined symbol warning..                 for the moment we give undefined symbol warning..
487           Should really go through the symbols, recording the external addr                 Should really go through the symbols, recording the external addr
488           for ones found in ptable, and for the ones not in ptable                 for ones found in ptable, and for the ones not in ptable
489           set some flag, and add up the extra_bss required.  Then                 set some flag, and add up the extra_bss required.  Then
490           when you have the new memory chunk in hand,                 when you have the new memory chunk in hand,
491           you could make the pass setting the relative addresses.                 you could make the pass setting the relative addresses.
492           for the ones you flagged last time.                 for the ones you flagged last time.
493        */                 */
494        /* external bss so not included in size of bss for file */              /* external bss so not included in size of bss for file */
495        {int val=sym->Value;              {int val=sym->Value;
496          if (val && c_table.ptable               if (val && c_table.ptable
497              && (0== find_sym(sym,0)))                    && (0== find_sym(sym,0)))
498            { sym->Value=result;                   { sym->Value=result;
499              result += val;}}                     result += val;}}
500                        
501      sym += sym->NumberOfAuxSymbols;          sym += sym->NumberOfAuxSymbols;
502    
503    }      }
504    return (result-start);      return (result-start);
505  }  }
506    
507    
# Line 519  void relocate_symbols ( unsigned int len Line 519  void relocate_symbols ( unsigned int len
519    
520      end = symbol_table + length;      end = symbol_table + length;
521      for ( sym = symbol_table; sym < end; sym++ ) {      for ( sym = symbol_table; sym < end; sym++ ) {
522        typ = sym->SectionNumber;          typ = sym->SectionNumber;
523    
524          if ( typ == TEXT_NSCN || typ == DATA_NSCN ||          if ( typ == TEXT_NSCN || typ == DATA_NSCN ||
525               typ == RDATA_NSCN || typ == BSS_NSCN ) {               typ == RDATA_NSCN || typ == BSS_NSCN ) {
526            if ( typ == TEXT_NSCN )  Value = (int)start_address;              if ( typ == TEXT_NSCN )  Value = (int)start_address;
527            if ( typ == DATA_NSCN )  Value = (int)sfaslp->s_start_data;              if ( typ == DATA_NSCN )  Value = (int)sfaslp->s_start_data;
528            if ( typ == RDATA_NSCN ) Value = (int)sfaslp->s_start_rdata;              if ( typ == RDATA_NSCN ) Value = (int)sfaslp->s_start_rdata;
529            if ( typ == BSS_NSCN )   Value = (int)sfaslp->s_start_bss;              if ( typ == BSS_NSCN )   Value = (int)sfaslp->s_start_bss;
           str=SYM_NAME(sym);  
           sym->Value = Value;  
         } else {  
           if ( typ == 0 ) {  
530              str=SYM_NAME(sym);              str=SYM_NAME(sym);
531              /* describe_sym ( sym-symbol_table, 0 );*/              sym->Value = Value;
532              set_symbol_address(sym,str);          } else {
533              /* describe_sym ( sym-symbol_table, 0 ); */              if ( typ == 0 ) {
534            } else {                  str=SYM_NAME(sym);
535              printf ("relocate_symbols: am ignoring section number %d\n",                  /* describe_sym ( sym-symbol_table, 0 );*/
536                     (sym->SectionNumber) );        }                  set_symbol_address(sym,str);
537                    /* describe_sym ( sym-symbol_table, 0 ); */
538                } else {
539                    printf ("relocate_symbols: am ignoring section number %d\n",
540                             (sym->SectionNumber) );          }
541          }          }
542          sym += sym->NumberOfAuxSymbols;          sym += sym->NumberOfAuxSymbols;
543      }      }
# Line 566  void set_symbol_address ( PIMAGE_SYMBOL Line 566  void set_symbol_address ( PIMAGE_SYMBOL
566      if ( c_table.ptable ) {      if ( c_table.ptable ) {
567          answ = find_sym(sym,string);          answ = find_sym(sym,string);
568          if ( answ ) {          if ( answ ) {
569                  sym->Value = answ->address - sym->Value;              sym->Value = answ->address - sym->Value;
570              /* for symbols in the local  data,text and bss this gets added              /* for symbols in the local  data,text and bss this gets added
571                 on when we add the current value */                 on when we add the current value */
572          } else {          } else {

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.5

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26