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