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.  */
45extern int ld_scan_version_script;
46
47#define MAX_PREPDEPTH 20
48static enum prepstate
49{
50  prep_normal,
51  skip_if,
52  skip_to_endif
53} prepstate[MAX_PREPDEPTH];
54static int prepdepth;
55
56static void eat_comment (void);
57static void eat_to_eol (bool empty);
58static int attrib_convert (int c);
59static void push_state (enum prepstate);
60static int pop_state (void);
61static int handle_ifdef (void);
62static void invalid_char (int ch);
63%}
64
65ID		[a-zA-Z0-9_.*?]+
66FILENAMECHAR1	[a-zA-Z0-9_/.\\~]
67FILENAMECHAR	[^][{}[:space:]():;]+
68HEX		0[xX][0-9a-fA-F]+[kKmM]?
69OCT		0[0-7]*[kKmM]?
70DEC		[0-9]+[kKmM]?
71WHITE		[[: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
121ALIGN				{ return kALIGN; }
122ENTRY				{ return kENTRY; }
123EXCLUDE_FILE			{ return kEXCLUDE_FILE; }
124"global:"			{ return kGLOBAL; }
125GROUP				{ return kGROUP; }
126INPUT				{ return kINPUT; }
127INTERP				{ return kINTERP; }
128KEEP				{ return kKEEP; }
129"local:"			{ return kLOCAL; }
130OUTPUT_FORMAT			{ return kOUTPUT_FORMAT; }
131PAGESIZE			{ return kPAGESIZE; }
132PROVIDE				{ return kPROVIDE; }
133SEARCH_DIR			{ return kSEARCH_DIR; }
134SEGMENT				{ return kSEGMENT; }
135SIZEOF_HEADERS			{ return kSIZEOF_HEADERS; }
136SORT				{ return kSORT; }
137VERSION				{ 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
190static void
191eat_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
219static void
220eat_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
245static int
246attrib_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
257static void
258push_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
268static int
269pop_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
280static int
281handle_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
331static void
332invalid_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