blob: 9e30a865361b02a502b66d9dbf1f93abb2316f1c [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001%{
2/* Copyright (C) 2001, 2002, 2003, 2004, 2005 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/* ECHO must be redefined since the default implementation ignores
45 the return value of fwrite_unlocked. */
46#define ECHO do { size_t n__ __attribute__ ((unused)) \
47 = fwrite (yytext, yyleng, 1, yyout); } while (0)
48
49/* Defined in ld.c. */
50extern int ld_scan_version_script;
51
52#define MAX_PREPDEPTH 20
53static enum prepstate
54{
55 prep_normal,
56 skip_if,
57 skip_to_endif
58} prepstate[MAX_PREPDEPTH];
59static int prepdepth;
60
61static void eat_comment (void);
62static void eat_to_eol (bool empty);
63static int attrib_convert (int c);
64static void push_state (enum prepstate);
65static int pop_state (void);
66static int handle_ifdef (void);
67static void invalid_char (int ch);
68%}
69
70ID [a-zA-Z0-9_.*?]+
71FILENAMECHAR1 [a-zA-Z0-9_/.\\~]
72FILENAMECHAR [^][{}[:space:]():;]+
73HEX 0[xX][0-9a-fA-F]+[kKmM]?
74OCT 0[0-7]*[kKmM]?
75DEC [0-9]+[kKmM]?
76WHITE [[:space:]]+
77
78%option yylineno
79%option never-interactive
80%option noyywrap
81
82%x IGNORE
83
84%%
85 if (unlikely (ld_scan_version_script))
86 {
87 ld_scan_version_script = -1;
88 return kVERSION_SCRIPT;
89 }
90
91^"#"ifdef/[[:space:]] { BEGIN (handle_ifdef ()); }
92^"#"else/[[:space:]\n] { eat_to_eol (true);
93 push_state (skip_to_endif);
94 BEGIN (IGNORE); }
95^"#"elifdef/[[:space:]] { eat_to_eol (false);
96 push_state (skip_to_endif);
97 BEGIN (IGNORE); }
98^"#"endif/[[:space:]\n] { eat_to_eol (true) ; }
99
100<IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false);
101 push_state (skip_to_endif); }
102<IGNORE>^"#"else/[[:space:]\n] { eat_to_eol (true);
103 assert (prepdepth > 0);
104 if (prepstate[prepdepth - 1] == skip_if)
105 {
106 /* Back to normal processing. */
107 assert (prepdepth == 1);
108 BEGIN (pop_state ());
109 }
110 }
111<IGNORE>^"#"elifdef/[[:space:]] { assert (prepdepth > 0);
112 if (prepstate[prepdepth - 1] == skip_if)
113 {
114 /* Maybe this symbol is defined. */
115 pop_state ();
116 BEGIN (handle_ifdef ());
117 }
118 }
119<IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true);
120 BEGIN (pop_state ()); }
121<IGNORE>.|\n { /* nothing */ }
122
123
124"/*" { eat_comment (); }
125
126ALIGN { return kALIGN; }
127AS_NEEDED { return kAS_NEEDED; }
128ENTRY { return kENTRY; }
129EXCLUDE_FILE { return kEXCLUDE_FILE; }
130"global:" { return kGLOBAL; }
131GROUP { return kGROUP; }
132INPUT { return kINPUT; }
133INTERP { return kINTERP; }
134KEEP { return kKEEP; }
135"local:" { return kLOCAL; }
136OUTPUT_FORMAT { return kOUTPUT_FORMAT; }
137PAGESIZE { return kPAGESIZE; }
138PROVIDE { return kPROVIDE; }
139SEARCH_DIR { return kSEARCH_DIR; }
140SEGMENT { return kSEGMENT; }
141SIZEOF_HEADERS { return kSIZEOF_HEADERS; }
142SORT { return kSORT; }
143VERSION { return kVERSION; }
144
145"["([RWX]){0,3}"]" { int cnt = 1 ;
146 ldlval.num = 0;
147 while (cnt < yyleng - 1)
148 ldlval.num |= attrib_convert (yytext[cnt++]);
149 return kMODE; }
150
151"{" { return '{'; }
152"}" { return '}'; }
153"(" { return '('; }
154")" { return ')'; }
155":" { return ':'; }
156";" { return ';'; }
157"=" { return '='; }
158"+" { ldlval.op = exp_plus; return kADD_OP; }
159"-" { ldlval.op = exp_minus; return kADD_OP; }
160"*" { return '*'; }
161"/" { ldlval.op = exp_div; return kMUL_OP; }
162"%" { ldlval.op = exp_mod; return kMUL_OP; }
163"&" { return '&'; }
164"|" { return '|'; }
165
166"," { return ','; }
167
168{HEX}|{OCT}|{DEC} { char *endp;
169 ldlval.num = strtoumax (yytext, &endp, 0);
170 if (*endp != '\0')
171 {
172 if (tolower (*endp) == 'k')
173 ldlval.num *= 1024;
174 else
175 {
176 assert (tolower (*endp) == 'm');
177 ldlval.num *= 1024 * 1024;
178 }
179 }
180 return kNUM; }
181
182{ID} { ldlval.str = obstack_strndup (&ld_state.smem,
183 yytext, yyleng);
184 return kID; }
185
186{FILENAMECHAR1}{FILENAMECHAR} { ldlval.str = obstack_strndup (&ld_state.smem,
187 yytext, yyleng);
188 return kFILENAME; }
189
190{WHITE} { /* IGNORE */ }
191
192. { invalid_char (*yytext); }
193
194%%
195
196static void
197eat_comment (void)
198{
199 while (1)
200 {
201 int c = input ();
202
203 while (c != '*' && c != EOF)
204 c = input ();
205
206 if (c == '*')
207 {
208 c = input ();
209 while (c == '*')
210 c = input ();
211 if (c == '/')
212 break;
213 }
214
215 if (c == EOF)
216 {
217 /* XXX Use the setjmp buffer and signal EOF in comment */
218 error (0, 0, gettext ("EOF in comment"));
219 break;
220 }
221 }
222}
223
224
225static void
226eat_to_eol (bool empty)
227{
228 bool warned = false;
229
230 while (1)
231 {
232 int c = input ();
233
234 if (c == EOF)
235 break;
236 if (c == '\n')
237 {
238 ++yylineno;
239 break;
240 }
241
242 if (empty && ! isspace (c) && ! warned)
243 {
244 error (0, 0, gettext ("%d: garbage at end of line"), yylineno);
245 warned = true;
246 }
247 }
248}
249
250
251static int
252attrib_convert (int c)
253{
254 if (c == 'X')
255 return PF_X;
256 if (c == 'W')
257 return PF_W;
258 assert (c == 'R');
259 return PF_R;
260}
261
262
263static void
264push_state (enum prepstate state)
265{
266 if (prepdepth >= MAX_PREPDEPTH)
267 error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"),
268 yylineno);
269
270 prepstate[prepdepth++] = state;
271}
272
273
274static int
275pop_state (void)
276{
277 if (prepdepth == 0)
278 error (0, 0, gettext ("%d: unexpected #endif"), yylineno);
279 else
280 --prepdepth;
281
282 return prepdepth == 0 ? INITIAL : IGNORE;
283}
284
285
286static int
287handle_ifdef (void)
288{
289 char idbuf[50];
290 char *id = idbuf;
291 size_t idlen = 0;
292 size_t idmax = sizeof (idbuf);
293 bool ignore_ws = true;
294 bool defined = false;
295 int result;
296
297 while (1)
298 {
299 int c = input ();
300
301 if (isspace (c) && ignore_ws)
302 continue;
303
304 if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')
305 && (idlen == 0 || c < '0' || c > '9'))
306 {
307 unput (c);
308 break;
309 }
310
311 if (idlen == idmax)
312 {
313 char *newp = (char *) alloca (idmax *= 2);
314 id = memcpy (newp, id, idlen);
315 }
316
317 id[idlen++] = c;
318 ignore_ws = false;
319 }
320
321 /* XXX Compare in a better way. */
322 if (idlen == 6 && strncmp (id, "SHARED", 6) == 0)
323 defined = ld_state.file_type == dso_file_type;
324
325 if (defined)
326 result = INITIAL;
327 else
328 {
329 push_state (skip_if);
330 result = IGNORE;
331 }
332
333 return result;
334}
335
336
337static void
338invalid_char (int ch)
339{
340 error (0, 0, (isascii (ch)
341 ? gettext ("invalid character '%c' at line %d; ignored")
342 : gettext ("invalid character '\\%o' at line %d; ignored")),
343 ch, yylineno);
344}
345
346
347// Local Variables:
348// mode: C
349// End: