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