• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 %{
2 /* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@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
eat_to_eol(bool empty)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
attrib_convert(int c)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
push_state(enum prepstate state)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
pop_state(void)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
handle_ifdef(void)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
invalid_char(int ch)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