Home | History | Annotate | Download | only in src
      1 %{
      2 /* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2001.
      4 
      5    This program is Open Source software; you can redistribute it and/or
      6    modify it under the terms of the Open Software License version 1.0 as
      7    published by the Open Source Initiative.
      8 
      9    You should have received a copy of the Open Software License along
     10    with this program; if not, you may obtain a copy of the Open Software
     11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     13    3001 King Ranch Road, Ukiah, CA 95482.   */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 # include <config.h>
     17 #endif
     18 
     19 #include <assert.h>
     20 #include <ctype.h>
     21 #include <elf.h>
     22 #include <error.h>
     23 #include <inttypes.h>
     24 #include <libintl.h>
     25 #include <stdbool.h>
     26 #include <stdio.h>
     27 #include <string.h>
     28 
     29 #include <system.h>
     30 #include <ld.h>
     31 #include "ldscript.h"
     32 
     33 /* We sure use no threads to read the stream, so use the _unlocked
     34    variants of the functions.  */
     35 #undef getc
     36 #define getc(s) getc_unlocked (s)
     37 #undef ferror
     38 #define ferror(s) ferror_unlocked (s)
     39 #undef fread
     40 #define fread(b, m, n, s) fread_unlocked (b, m, n, s)
     41 #undef fwrite
     42 #define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s)
     43 
     44 /* Defined in ld.c.  */
     45 extern int ld_scan_version_script;
     46 
     47 #define MAX_PREPDEPTH 20
     48 static enum prepstate
     49 {
     50   prep_normal,
     51   skip_if,
     52   skip_to_endif
     53 } prepstate[MAX_PREPDEPTH];
     54 static int prepdepth;
     55 
     56 static void eat_comment (void);
     57 static void eat_to_eol (bool empty);
     58 static int attrib_convert (int c);
     59 static void push_state (enum prepstate);
     60 static int pop_state (void);
     61 static int handle_ifdef (void);
     62 static void invalid_char (int ch);
     63 %}
     64 
     65 ID		[a-zA-Z0-9_.*?]+
     66 FILENAMECHAR1	[a-zA-Z0-9_/.\\~]
     67 FILENAMECHAR	[^][{}[:space:]():;]+
     68 HEX		0[xX][0-9a-fA-F]+[kKmM]?
     69 OCT		0[0-7]*[kKmM]?
     70 DEC		[0-9]+[kKmM]?
     71 WHITE		[[:space:]]+
     72 
     73 %option yylineno
     74 %option never-interactive
     75 %option noyywrap
     76 
     77 %x IGNORE
     78 
     79 %%
     80 				if (unlikely (ld_scan_version_script))
     81 				  {
     82 				    ld_scan_version_script = -1;
     83 				    return kVERSION_SCRIPT;
     84 				  }
     85 
     86 ^"#"ifdef/[[:space:]]		{ BEGIN (handle_ifdef ()); }
     87 ^"#"else/[[:space:]\n]		{ eat_to_eol (true);
     88 				  push_state (skip_to_endif);
     89 				  BEGIN (IGNORE); }
     90 ^"#"elifdef/[[:space:]]		{ eat_to_eol (false);
     91 				  push_state (skip_to_endif);
     92 				  BEGIN (IGNORE); }
     93 ^"#"endif/[[:space:]\n]		{ eat_to_eol (true) ; }
     94 
     95 <IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false);
     96 				  push_state (skip_to_endif); }
     97 <IGNORE>^"#"else/[[:space:]\n]	{ eat_to_eol (true);
     98 				  assert (prepdepth > 0);
     99 				  if (prepstate[prepdepth - 1] == skip_if)
    100 				    {
    101 				      /* Back to normal processing.  */
    102 				      assert (prepdepth == 1);
    103 				      BEGIN (pop_state ());
    104 				    }
    105 				}
    106 <IGNORE>^"#"elifdef/[[:space:]]	{ assert (prepdepth > 0);
    107 				  if (prepstate[prepdepth - 1] == skip_if)
    108 				    {
    109 				      /* Maybe this symbol is defined.  */
    110 				      pop_state ();
    111 				      BEGIN (handle_ifdef ());
    112 				    }
    113 				}
    114 <IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true);
    115 				  BEGIN (pop_state ()); }
    116 <IGNORE>.|\n			{ /* nothing */ }
    117 
    118 
    119 "/*"				{ eat_comment (); }
    120 
    121 ALIGN				{ return kALIGN; }
    122 ENTRY				{ return kENTRY; }
    123 EXCLUDE_FILE			{ return kEXCLUDE_FILE; }
    124 "global:"			{ return kGLOBAL; }
    125 GROUP				{ return kGROUP; }
    126 INPUT				{ return kINPUT; }
    127 INTERP				{ return kINTERP; }
    128 KEEP				{ return kKEEP; }
    129 "local:"			{ return kLOCAL; }
    130 OUTPUT_FORMAT			{ return kOUTPUT_FORMAT; }
    131 PAGESIZE			{ return kPAGESIZE; }
    132 PROVIDE				{ return kPROVIDE; }
    133 SEARCH_DIR			{ return kSEARCH_DIR; }
    134 SEGMENT				{ return kSEGMENT; }
    135 SIZEOF_HEADERS			{ return kSIZEOF_HEADERS; }
    136 SORT				{ return kSORT; }
    137 VERSION				{ return kVERSION; }
    138 
    139 "["([RWX]){0,3}"]"		{ int cnt = 1 ;
    140 				  ldlval.num = 0;
    141 				  while (cnt < yyleng - 1)
    142 				    ldlval.num |= attrib_convert (yytext[cnt++]);
    143 				  return kMODE; }
    144 
    145 "{"				{ return '{'; }
    146 "}"				{ return '}'; }
    147 "("				{ return '('; }
    148 ")"				{ return ')'; }
    149 ":"				{ return ':'; }
    150 ";"				{ return ';'; }
    151 "="				{ return '='; }
    152 "+"				{ ldlval.op = exp_plus; return kADD_OP; }
    153 "-"				{ ldlval.op = exp_minus; return kADD_OP; }
    154 "*"				{ return '*'; }
    155 "/"				{ ldlval.op = exp_div; return kMUL_OP; }
    156 "%"				{ ldlval.op = exp_mod; return kMUL_OP; }
    157 "&"				{ return '&'; }
    158 "|"				{ return '|'; }
    159 
    160 ","				{ return ','; }
    161 
    162 {HEX}|{OCT}|{DEC}		{ char *endp;
    163 				  ldlval.num = strtoumax (yytext, &endp, 0);
    164 				  if (*endp != '\0')
    165 				    {
    166 				      if (tolower (*endp) == 'k')
    167 					ldlval.num *= 1024;
    168 				      else
    169 					{
    170 					  assert (tolower (*endp) == 'm');
    171 					  ldlval.num *= 1024 * 1024;
    172 					}
    173 				    }
    174 				  return kNUM; }
    175 
    176 {ID}				{ ldlval.str = obstack_strndup (&ld_state.smem,
    177 								yytext, yyleng);
    178 				  return kID; }
    179 
    180 {FILENAMECHAR1}{FILENAMECHAR}	{ ldlval.str = obstack_strndup (&ld_state.smem,
    181 								yytext, yyleng);
    182 				  return kFILENAME; }
    183 
    184 {WHITE}				{ /* IGNORE */ }
    185 
    186 .				{ invalid_char (*yytext); }
    187 
    188 %%
    189 
    190 static void
    191 eat_comment (void)
    192 {
    193   while (1)
    194     {
    195       int c = input ();
    196 
    197       while (c != '*' && c != EOF)
    198 	c = input ();
    199 
    200       if (c == '*')
    201 	{
    202 	  c = input ();
    203 	  while (c == '*')
    204 	    c = input ();
    205 	  if (c == '/')
    206 	    break;
    207 	}
    208 
    209       if (c == EOF)
    210 	{
    211 	  /* XXX Use the setjmp buffer and signal EOF in comment */
    212 	  error (0, 0, gettext ("EOF in comment"));
    213 	  break;
    214 	}
    215     }
    216 }
    217 
    218 
    219 static void
    220 eat_to_eol (bool empty)
    221 {
    222   bool warned = false;
    223 
    224   while (1)
    225     {
    226       int c = input ();
    227 
    228       if (c == EOF)
    229 	break;
    230       if (c == '\n')
    231 	{
    232 	  ++yylineno;
    233 	  break;
    234 	}
    235 
    236       if (empty && ! isspace (c) && ! warned)
    237 	{
    238 	  error (0, 0, gettext ("%d: garbage at end of line"), yylineno);
    239 	  warned = true;
    240 	}
    241     }
    242 }
    243 
    244 
    245 static int
    246 attrib_convert (int c)
    247 {
    248   if (c == 'X')
    249     return PF_X;
    250   if (c == 'W')
    251     return PF_W;
    252   assert (c == 'R');
    253   return PF_R;
    254 }
    255 
    256 
    257 static void
    258 push_state (enum prepstate state)
    259 {
    260   if (prepdepth >= MAX_PREPDEPTH)
    261     error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"),
    262 	   yylineno);
    263 
    264   prepstate[prepdepth++] = state;
    265 }
    266 
    267 
    268 static int
    269 pop_state (void)
    270 {
    271   if (prepdepth == 0)
    272     error (0, 0, gettext ("%d: unexpected #endif"), yylineno);
    273   else
    274     --prepdepth;
    275 
    276   return prepdepth == 0 ? INITIAL : IGNORE;
    277 }
    278 
    279 
    280 static int
    281 handle_ifdef (void)
    282 {
    283   char idbuf[50];
    284   char *id = idbuf;
    285   size_t idlen = 0;
    286   size_t idmax = sizeof (idbuf);
    287   bool ignore_ws = true;
    288   bool defined = false;
    289   int result;
    290 
    291   while (1)
    292     {
    293       int c = input ();
    294 
    295       if (isspace (c) && ignore_ws)
    296 	continue;
    297 
    298       if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')
    299 	  && (idlen == 0 || c < '0' || c > '9'))
    300 	{
    301 	  unput (c);
    302 	  break;
    303 	}
    304 
    305       if (idlen == idmax)
    306 	{
    307 	  char *newp = (char *) alloca (idmax *= 2);
    308 	  id = memcpy (newp, id, idlen);
    309 	}
    310 
    311       id[idlen++] = c;
    312       ignore_ws = false;
    313     }
    314 
    315   /* XXX Compare in a better way.  */
    316   if (idlen == 6 && strncmp (id, "SHARED", 6) == 0)
    317     defined = ld_state.file_type == dso_file_type;
    318 
    319   if (defined)
    320     result = INITIAL;
    321   else
    322     {
    323       push_state (skip_if);
    324       result = IGNORE;
    325     }
    326 
    327   return result;
    328 }
    329 
    330 
    331 static void
    332 invalid_char (int ch)
    333 {
    334   error (0, 0, (isascii (ch)
    335 		? gettext ("invalid character '%c' at line %d; ignored")
    336 		: gettext ("invalid character '\\%o' at line %d; ignored")),
    337 	 ch, yylineno);
    338 }
    339 
    340 
    341 // Local Variables:
    342 // mode: C
    343 // End:
    344