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