Commit | Line | Data |
---|---|---|
e5756efb ILT |
1 | // expression.cc -- expressions in linker scripts for gold |
2 | ||
3 | // Copyright 2006, 2007, 2008 Free Software Foundation, Inc. | |
4 | // Written by Ian Lance Taylor <iant@google.com>. | |
5 | ||
6 | // This file is part of gold. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or modify | |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 3 of the License, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
21 | // MA 02110-1301, USA. | |
22 | ||
23 | #include "gold.h" | |
24 | ||
25 | #include <string> | |
26 | ||
3802b2dd | 27 | #include "elfcpp.h" |
e5756efb ILT |
28 | #include "parameters.h" |
29 | #include "symtab.h" | |
30 | #include "layout.h" | |
494e05f4 | 31 | #include "output.h" |
e5756efb ILT |
32 | #include "script.h" |
33 | #include "script-c.h" | |
34 | ||
35 | namespace gold | |
36 | { | |
37 | ||
38 | // This file holds the code which handles linker expressions. | |
39 | ||
a445fddf ILT |
40 | // The dot symbol, which linker scripts refer to simply as ".", |
41 | // requires special treatment. The dot symbol is set several times, | |
42 | // section addresses will refer to it, output sections will change it, | |
43 | // and it can be set based on the value of other symbols. We simplify | |
44 | // the handling by prohibiting setting the dot symbol to the value of | |
45 | // a non-absolute symbol. | |
46 | ||
e5756efb ILT |
47 | // When evaluating the value of an expression, we pass in a pointer to |
48 | // this struct, so that the expression evaluation can find the | |
49 | // information it needs. | |
50 | ||
51 | struct Expression::Expression_eval_info | |
52 | { | |
a445fddf | 53 | // The symbol table. |
e5756efb | 54 | const Symbol_table* symtab; |
a445fddf | 55 | // The layout--we use this to get section information. |
e5756efb | 56 | const Layout* layout; |
919ed24c ILT |
57 | // Whether to check assertions. |
58 | bool check_assertions; | |
a445fddf ILT |
59 | // Whether expressions can refer to the dot symbol. The dot symbol |
60 | // is only available within a SECTIONS clause. | |
61 | bool is_dot_available; | |
a445fddf ILT |
62 | // The current value of the dot symbol. |
63 | uint64_t dot_value; | |
77e65537 ILT |
64 | // The section in which the dot symbol is defined; this is NULL if |
65 | // it is absolute. | |
66 | Output_section* dot_section; | |
67 | // Points to where the section of the result should be stored. | |
68 | Output_section** result_section_pointer; | |
e5756efb ILT |
69 | }; |
70 | ||
71 | // Evaluate an expression. | |
72 | ||
73 | uint64_t | |
919ed24c ILT |
74 | Expression::eval(const Symbol_table* symtab, const Layout* layout, |
75 | bool check_assertions) | |
a445fddf | 76 | { |
77e65537 | 77 | Output_section* dummy; |
919ed24c ILT |
78 | return this->eval_maybe_dot(symtab, layout, check_assertions, |
79 | false, 0, NULL, &dummy); | |
a445fddf ILT |
80 | } |
81 | ||
82 | // Evaluate an expression which may refer to the dot symbol. | |
83 | ||
84 | uint64_t | |
85 | Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, | |
919ed24c ILT |
86 | bool check_assertions, uint64_t dot_value, |
87 | Output_section* dot_section, | |
77e65537 | 88 | Output_section** result_section_pointer) |
a445fddf | 89 | { |
919ed24c ILT |
90 | return this->eval_maybe_dot(symtab, layout, check_assertions, true, |
91 | dot_value, dot_section, result_section_pointer); | |
a445fddf ILT |
92 | } |
93 | ||
94 | // Evaluate an expression which may or may not refer to the dot | |
95 | // symbol. | |
96 | ||
97 | uint64_t | |
98 | Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, | |
919ed24c ILT |
99 | bool check_assertions, bool is_dot_available, |
100 | uint64_t dot_value, Output_section* dot_section, | |
77e65537 | 101 | Output_section** result_section_pointer) |
e5756efb ILT |
102 | { |
103 | Expression_eval_info eei; | |
104 | eei.symtab = symtab; | |
105 | eei.layout = layout; | |
919ed24c | 106 | eei.check_assertions = check_assertions; |
a445fddf | 107 | eei.is_dot_available = is_dot_available; |
a445fddf | 108 | eei.dot_value = dot_value; |
77e65537 | 109 | eei.dot_section = dot_section; |
a445fddf | 110 | |
77e65537 ILT |
111 | // We assume the value is absolute, and only set this to a section |
112 | // if we find a section relative reference. | |
113 | *result_section_pointer = NULL; | |
114 | eei.result_section_pointer = result_section_pointer; | |
a445fddf | 115 | |
e5756efb ILT |
116 | return this->value(&eei); |
117 | } | |
118 | ||
119 | // A number. | |
120 | ||
121 | class Integer_expression : public Expression | |
122 | { | |
123 | public: | |
124 | Integer_expression(uint64_t val) | |
125 | : val_(val) | |
126 | { } | |
127 | ||
128 | uint64_t | |
129 | value(const Expression_eval_info*) | |
130 | { return this->val_; } | |
131 | ||
494e05f4 ILT |
132 | void |
133 | print(FILE* f) const | |
134 | { fprintf(f, "0x%llx", static_cast<unsigned long long>(this->val_)); } | |
135 | ||
e5756efb ILT |
136 | private: |
137 | uint64_t val_; | |
138 | }; | |
139 | ||
140 | extern "C" Expression* | |
141 | script_exp_integer(uint64_t val) | |
142 | { | |
143 | return new Integer_expression(val); | |
144 | } | |
145 | ||
146 | // An expression whose value is the value of a symbol. | |
147 | ||
148 | class Symbol_expression : public Expression | |
149 | { | |
150 | public: | |
151 | Symbol_expression(const char* name, size_t length) | |
152 | : name_(name, length) | |
153 | { } | |
154 | ||
155 | uint64_t | |
156 | value(const Expression_eval_info*); | |
157 | ||
494e05f4 ILT |
158 | void |
159 | print(FILE* f) const | |
160 | { fprintf(f, "%s", this->name_.c_str()); } | |
161 | ||
e5756efb ILT |
162 | private: |
163 | std::string name_; | |
164 | }; | |
165 | ||
166 | uint64_t | |
167 | Symbol_expression::value(const Expression_eval_info* eei) | |
168 | { | |
169 | Symbol* sym = eei->symtab->lookup(this->name_.c_str()); | |
170 | if (sym == NULL || !sym->is_defined()) | |
171 | { | |
172 | gold_error(_("undefined symbol '%s' referenced in expression"), | |
173 | this->name_.c_str()); | |
174 | return 0; | |
175 | } | |
176 | ||
77e65537 | 177 | *eei->result_section_pointer = sym->output_section(); |
a445fddf | 178 | |
8851ecca | 179 | if (parameters->target().get_size() == 32) |
e5756efb | 180 | return eei->symtab->get_sized_symbol<32>(sym)->value(); |
8851ecca | 181 | else if (parameters->target().get_size() == 64) |
e5756efb ILT |
182 | return eei->symtab->get_sized_symbol<64>(sym)->value(); |
183 | else | |
184 | gold_unreachable(); | |
185 | } | |
186 | ||
187 | // An expression whose value is the value of the special symbol ".". | |
188 | // This is only valid within a SECTIONS clause. | |
189 | ||
190 | class Dot_expression : public Expression | |
191 | { | |
192 | public: | |
193 | Dot_expression() | |
194 | { } | |
195 | ||
196 | uint64_t | |
197 | value(const Expression_eval_info*); | |
494e05f4 ILT |
198 | |
199 | void | |
200 | print(FILE* f) const | |
201 | { fprintf(f, "."); } | |
e5756efb ILT |
202 | }; |
203 | ||
204 | uint64_t | |
a445fddf | 205 | Dot_expression::value(const Expression_eval_info* eei) |
e5756efb | 206 | { |
a445fddf ILT |
207 | if (!eei->is_dot_available) |
208 | { | |
209 | gold_error(_("invalid reference to dot symbol outside of " | |
210 | "SECTIONS clause")); | |
211 | return 0; | |
212 | } | |
77e65537 | 213 | *eei->result_section_pointer = eei->dot_section; |
a445fddf | 214 | return eei->dot_value; |
e5756efb ILT |
215 | } |
216 | ||
217 | // A string. This is either the name of a symbol, or ".". | |
218 | ||
219 | extern "C" Expression* | |
220 | script_exp_string(const char* name, size_t length) | |
221 | { | |
222 | if (length == 1 && name[0] == '.') | |
223 | return new Dot_expression(); | |
224 | else | |
225 | return new Symbol_expression(name, length); | |
226 | } | |
227 | ||
228 | // A unary expression. | |
229 | ||
230 | class Unary_expression : public Expression | |
231 | { | |
232 | public: | |
233 | Unary_expression(Expression* arg) | |
234 | : arg_(arg) | |
235 | { } | |
236 | ||
237 | ~Unary_expression() | |
238 | { delete this->arg_; } | |
239 | ||
240 | protected: | |
241 | uint64_t | |
77e65537 ILT |
242 | arg_value(const Expression_eval_info* eei, |
243 | Output_section** arg_section_pointer) const | |
244 | { | |
245 | return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 246 | eei->check_assertions, |
77e65537 ILT |
247 | eei->is_dot_available, |
248 | eei->dot_value, | |
249 | eei->dot_section, | |
250 | arg_section_pointer); | |
251 | } | |
e5756efb | 252 | |
494e05f4 ILT |
253 | void |
254 | arg_print(FILE* f) const | |
255 | { this->arg_->print(f); } | |
256 | ||
e5756efb ILT |
257 | private: |
258 | Expression* arg_; | |
259 | }; | |
260 | ||
261 | // Handle unary operators. We use a preprocessor macro as a hack to | |
262 | // capture the C operator. | |
263 | ||
77e65537 ILT |
264 | #define UNARY_EXPRESSION(NAME, OPERATOR) \ |
265 | class Unary_ ## NAME : public Unary_expression \ | |
266 | { \ | |
267 | public: \ | |
268 | Unary_ ## NAME(Expression* arg) \ | |
269 | : Unary_expression(arg) \ | |
270 | { } \ | |
271 | \ | |
272 | uint64_t \ | |
273 | value(const Expression_eval_info* eei) \ | |
274 | { \ | |
275 | Output_section* arg_section; \ | |
276 | uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ | |
8851ecca | 277 | if (arg_section != NULL && parameters->options().relocatable()) \ |
77e65537 ILT |
278 | gold_warning(_("unary " #NAME " applied to section " \ |
279 | "relative value")); \ | |
280 | return ret; \ | |
281 | } \ | |
282 | \ | |
283 | void \ | |
284 | print(FILE* f) const \ | |
285 | { \ | |
286 | fprintf(f, "(%s ", #OPERATOR); \ | |
287 | this->arg_print(f); \ | |
288 | fprintf(f, ")"); \ | |
289 | } \ | |
290 | }; \ | |
291 | \ | |
292 | extern "C" Expression* \ | |
293 | script_exp_unary_ ## NAME(Expression* arg) \ | |
294 | { \ | |
295 | return new Unary_ ## NAME(arg); \ | |
e5756efb ILT |
296 | } |
297 | ||
298 | UNARY_EXPRESSION(minus, -) | |
299 | UNARY_EXPRESSION(logical_not, !) | |
300 | UNARY_EXPRESSION(bitwise_not, ~) | |
301 | ||
302 | // A binary expression. | |
303 | ||
304 | class Binary_expression : public Expression | |
305 | { | |
306 | public: | |
307 | Binary_expression(Expression* left, Expression* right) | |
308 | : left_(left), right_(right) | |
309 | { } | |
310 | ||
311 | ~Binary_expression() | |
312 | { | |
313 | delete this->left_; | |
314 | delete this->right_; | |
315 | } | |
316 | ||
317 | protected: | |
318 | uint64_t | |
77e65537 ILT |
319 | left_value(const Expression_eval_info* eei, |
320 | Output_section** section_pointer) const | |
321 | { | |
322 | return this->left_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 323 | eei->check_assertions, |
77e65537 ILT |
324 | eei->is_dot_available, |
325 | eei->dot_value, | |
326 | eei->dot_section, | |
327 | section_pointer); | |
328 | } | |
e5756efb ILT |
329 | |
330 | uint64_t | |
77e65537 ILT |
331 | right_value(const Expression_eval_info* eei, |
332 | Output_section** section_pointer) const | |
333 | { | |
334 | return this->right_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 335 | eei->check_assertions, |
77e65537 ILT |
336 | eei->is_dot_available, |
337 | eei->dot_value, | |
338 | eei->dot_section, | |
339 | section_pointer); | |
340 | } | |
e5756efb | 341 | |
494e05f4 ILT |
342 | void |
343 | left_print(FILE* f) const | |
344 | { this->left_->print(f); } | |
345 | ||
346 | void | |
347 | right_print(FILE* f) const | |
348 | { this->right_->print(f); } | |
349 | ||
350 | // This is a call to function FUNCTION_NAME. Print it. This is for | |
351 | // debugging. | |
352 | void | |
353 | print_function(FILE* f, const char *function_name) const | |
354 | { | |
355 | fprintf(f, "%s(", function_name); | |
356 | this->left_print(f); | |
357 | fprintf(f, ", "); | |
358 | this->right_print(f); | |
359 | fprintf(f, ")"); | |
360 | } | |
361 | ||
e5756efb ILT |
362 | private: |
363 | Expression* left_; | |
364 | Expression* right_; | |
365 | }; | |
366 | ||
367 | // Handle binary operators. We use a preprocessor macro as a hack to | |
77e65537 ILT |
368 | // capture the C operator. KEEP_LEFT means that if the left operand |
369 | // is section relative and the right operand is not, the result uses | |
370 | // the same section as the left operand. KEEP_RIGHT is the same with | |
371 | // left and right swapped. IS_DIV means that we need to give an error | |
372 | // if the right operand is zero. WARN means that we should warn if | |
373 | // used on section relative values in a relocatable link. We always | |
374 | // warn if used on values in different sections in a relocatable link. | |
375 | ||
376 | #define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ | |
e5756efb ILT |
377 | class Binary_ ## NAME : public Binary_expression \ |
378 | { \ | |
379 | public: \ | |
380 | Binary_ ## NAME(Expression* left, Expression* right) \ | |
381 | : Binary_expression(left, right) \ | |
382 | { } \ | |
383 | \ | |
384 | uint64_t \ | |
385 | value(const Expression_eval_info* eei) \ | |
386 | { \ | |
77e65537 ILT |
387 | Output_section* left_section; \ |
388 | uint64_t left = this->left_value(eei, &left_section); \ | |
389 | Output_section* right_section; \ | |
390 | uint64_t right = this->right_value(eei, &right_section); \ | |
391 | if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ | |
392 | *eei->result_section_pointer = right_section; \ | |
393 | else if (KEEP_LEFT \ | |
394 | && left_section != NULL \ | |
395 | && right_section == NULL) \ | |
396 | *eei->result_section_pointer = left_section; \ | |
397 | else if ((WARN || left_section != right_section) \ | |
398 | && (left_section != NULL || right_section != NULL) \ | |
8851ecca | 399 | && parameters->options().relocatable()) \ |
77e65537 ILT |
400 | gold_warning(_("binary " #NAME " applied to section " \ |
401 | "relative value")); \ | |
402 | if (IS_DIV && right == 0) \ | |
403 | { \ | |
404 | gold_error(_(#NAME " by zero")); \ | |
405 | return 0; \ | |
406 | } \ | |
407 | return left OPERATOR right; \ | |
494e05f4 ILT |
408 | } \ |
409 | \ | |
410 | void \ | |
411 | print(FILE* f) const \ | |
412 | { \ | |
413 | fprintf(f, "("); \ | |
414 | this->left_print(f); \ | |
415 | fprintf(f, " %s ", #OPERATOR); \ | |
416 | this->right_print(f); \ | |
417 | fprintf(f, ")"); \ | |
e5756efb ILT |
418 | } \ |
419 | }; \ | |
420 | \ | |
421 | extern "C" Expression* \ | |
422 | script_exp_binary_ ## NAME(Expression* left, Expression* right) \ | |
423 | { \ | |
424 | return new Binary_ ## NAME(left, right); \ | |
425 | } | |
426 | ||
77e65537 ILT |
427 | BINARY_EXPRESSION(mult, *, false, false, false, true) |
428 | BINARY_EXPRESSION(div, /, false, false, true, true) | |
429 | BINARY_EXPRESSION(mod, %, false, false, true, true) | |
430 | BINARY_EXPRESSION(add, +, true, true, false, true) | |
431 | BINARY_EXPRESSION(sub, -, true, false, false, false) | |
432 | BINARY_EXPRESSION(lshift, <<, false, false, false, true) | |
433 | BINARY_EXPRESSION(rshift, >>, false, false, false, true) | |
434 | BINARY_EXPRESSION(eq, ==, false, false, false, false) | |
435 | BINARY_EXPRESSION(ne, !=, false, false, false, false) | |
436 | BINARY_EXPRESSION(le, <=, false, false, false, false) | |
437 | BINARY_EXPRESSION(ge, >=, false, false, false, false) | |
438 | BINARY_EXPRESSION(lt, <, false, false, false, false) | |
439 | BINARY_EXPRESSION(gt, >, false, false, false, false) | |
440 | BINARY_EXPRESSION(bitwise_and, &, true, true, false, true) | |
441 | BINARY_EXPRESSION(bitwise_xor, ^, true, true, false, true) | |
442 | BINARY_EXPRESSION(bitwise_or, |, true, true, false, true) | |
443 | BINARY_EXPRESSION(logical_and, &&, false, false, false, true) | |
444 | BINARY_EXPRESSION(logical_or, ||, false, false, false, true) | |
e5756efb ILT |
445 | |
446 | // A trinary expression. | |
447 | ||
448 | class Trinary_expression : public Expression | |
449 | { | |
450 | public: | |
451 | Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3) | |
452 | : arg1_(arg1), arg2_(arg2), arg3_(arg3) | |
453 | { } | |
454 | ||
455 | ~Trinary_expression() | |
456 | { | |
457 | delete this->arg1_; | |
458 | delete this->arg2_; | |
459 | delete this->arg3_; | |
460 | } | |
461 | ||
462 | protected: | |
463 | uint64_t | |
77e65537 ILT |
464 | arg1_value(const Expression_eval_info* eei, |
465 | Output_section** section_pointer) const | |
466 | { | |
467 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 468 | eei->check_assertions, |
77e65537 ILT |
469 | eei->is_dot_available, |
470 | eei->dot_value, | |
471 | eei->dot_section, | |
472 | section_pointer); | |
473 | } | |
e5756efb ILT |
474 | |
475 | uint64_t | |
77e65537 ILT |
476 | arg2_value(const Expression_eval_info* eei, |
477 | Output_section** section_pointer) const | |
478 | { | |
479 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 480 | eei->check_assertions, |
77e65537 ILT |
481 | eei->is_dot_available, |
482 | eei->dot_value, | |
483 | eei->dot_section, | |
484 | section_pointer); | |
485 | } | |
e5756efb ILT |
486 | |
487 | uint64_t | |
77e65537 ILT |
488 | arg3_value(const Expression_eval_info* eei, |
489 | Output_section** section_pointer) const | |
490 | { | |
491 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 492 | eei->check_assertions, |
77e65537 ILT |
493 | eei->is_dot_available, |
494 | eei->dot_value, | |
495 | eei->dot_section, | |
496 | section_pointer); | |
497 | } | |
e5756efb | 498 | |
494e05f4 ILT |
499 | void |
500 | arg1_print(FILE* f) const | |
501 | { this->arg1_->print(f); } | |
502 | ||
503 | void | |
504 | arg2_print(FILE* f) const | |
505 | { this->arg2_->print(f); } | |
506 | ||
507 | void | |
508 | arg3_print(FILE* f) const | |
509 | { this->arg3_->print(f); } | |
510 | ||
e5756efb ILT |
511 | private: |
512 | Expression* arg1_; | |
513 | Expression* arg2_; | |
514 | Expression* arg3_; | |
515 | }; | |
516 | ||
517 | // The conditional operator. | |
518 | ||
519 | class Trinary_cond : public Trinary_expression | |
520 | { | |
521 | public: | |
522 | Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
523 | : Trinary_expression(arg1, arg2, arg3) | |
524 | { } | |
525 | ||
526 | uint64_t | |
527 | value(const Expression_eval_info* eei) | |
528 | { | |
77e65537 ILT |
529 | Output_section* arg1_section; |
530 | uint64_t arg1 = this->arg1_value(eei, &arg1_section); | |
531 | return (arg1 | |
532 | ? this->arg2_value(eei, eei->result_section_pointer) | |
533 | : this->arg3_value(eei, eei->result_section_pointer)); | |
e5756efb | 534 | } |
494e05f4 ILT |
535 | |
536 | void | |
537 | print(FILE* f) const | |
538 | { | |
539 | fprintf(f, "("); | |
540 | this->arg1_print(f); | |
541 | fprintf(f, " ? "); | |
542 | this->arg2_print(f); | |
543 | fprintf(f, " : "); | |
544 | this->arg3_print(f); | |
545 | fprintf(f, ")"); | |
546 | } | |
e5756efb ILT |
547 | }; |
548 | ||
549 | extern "C" Expression* | |
550 | script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
551 | { | |
552 | return new Trinary_cond(arg1, arg2, arg3); | |
553 | } | |
554 | ||
555 | // Max function. | |
556 | ||
557 | class Max_expression : public Binary_expression | |
558 | { | |
559 | public: | |
560 | Max_expression(Expression* left, Expression* right) | |
561 | : Binary_expression(left, right) | |
562 | { } | |
563 | ||
564 | uint64_t | |
565 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
566 | { |
567 | Output_section* left_section; | |
568 | uint64_t left = this->left_value(eei, &left_section); | |
569 | Output_section* right_section; | |
570 | uint64_t right = this->right_value(eei, &right_section); | |
571 | if (left_section == right_section) | |
572 | *eei->result_section_pointer = left_section; | |
573 | else if ((left_section != NULL || right_section != NULL) | |
8851ecca | 574 | && parameters->options().relocatable()) |
77e65537 ILT |
575 | gold_warning(_("max applied to section relative value")); |
576 | return std::max(left, right); | |
577 | } | |
494e05f4 ILT |
578 | |
579 | void | |
580 | print(FILE* f) const | |
581 | { this->print_function(f, "MAX"); } | |
e5756efb ILT |
582 | }; |
583 | ||
584 | extern "C" Expression* | |
585 | script_exp_function_max(Expression* left, Expression* right) | |
586 | { | |
587 | return new Max_expression(left, right); | |
588 | } | |
589 | ||
590 | // Min function. | |
591 | ||
592 | class Min_expression : public Binary_expression | |
593 | { | |
594 | public: | |
595 | Min_expression(Expression* left, Expression* right) | |
596 | : Binary_expression(left, right) | |
597 | { } | |
598 | ||
599 | uint64_t | |
600 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
601 | { |
602 | Output_section* left_section; | |
603 | uint64_t left = this->left_value(eei, &left_section); | |
604 | Output_section* right_section; | |
605 | uint64_t right = this->right_value(eei, &right_section); | |
606 | if (left_section == right_section) | |
607 | *eei->result_section_pointer = left_section; | |
608 | else if ((left_section != NULL || right_section != NULL) | |
8851ecca | 609 | && parameters->options().relocatable()) |
77e65537 ILT |
610 | gold_warning(_("min applied to section relative value")); |
611 | return std::min(left, right); | |
612 | } | |
494e05f4 ILT |
613 | |
614 | void | |
615 | print(FILE* f) const | |
616 | { this->print_function(f, "MIN"); } | |
e5756efb ILT |
617 | }; |
618 | ||
619 | extern "C" Expression* | |
620 | script_exp_function_min(Expression* left, Expression* right) | |
621 | { | |
622 | return new Min_expression(left, right); | |
623 | } | |
624 | ||
7508a093 ILT |
625 | // Class Section_expression. This is a parent class used for |
626 | // functions which take the name of an output section. | |
627 | ||
628 | class Section_expression : public Expression | |
629 | { | |
630 | public: | |
631 | Section_expression(const char* section_name, size_t section_name_len) | |
632 | : section_name_(section_name, section_name_len) | |
633 | { } | |
634 | ||
635 | uint64_t | |
636 | value(const Expression_eval_info*); | |
637 | ||
638 | void | |
639 | print(FILE* f) const | |
640 | { fprintf(f, "%s(%s)", this->function_name(), this->section_name_.c_str()); } | |
641 | ||
642 | protected: | |
643 | // The child class must implement this. | |
644 | virtual uint64_t | |
645 | value_from_output_section(const Expression_eval_info*, | |
646 | Output_section*) = 0; | |
647 | ||
648 | // The child class must implement this. | |
649 | virtual const char* | |
650 | function_name() const = 0; | |
651 | ||
652 | private: | |
653 | std::string section_name_; | |
654 | }; | |
655 | ||
656 | uint64_t | |
657 | Section_expression::value(const Expression_eval_info* eei) | |
658 | { | |
659 | const char* section_name = this->section_name_.c_str(); | |
660 | Output_section* os = eei->layout->find_output_section(section_name); | |
661 | if (os == NULL) | |
662 | { | |
663 | gold_error("%s called on nonexistent output section '%s'", | |
664 | this->function_name(), section_name); | |
665 | return 0; | |
666 | } | |
667 | ||
668 | return this->value_from_output_section(eei, os); | |
669 | } | |
670 | ||
3edc73f2 ILT |
671 | // ABSOLUTE function. |
672 | ||
673 | class Absolute_expression : public Unary_expression | |
674 | { | |
675 | public: | |
676 | Absolute_expression(Expression* arg) | |
677 | : Unary_expression(arg) | |
678 | { } | |
679 | ||
680 | uint64_t | |
681 | value(const Expression_eval_info* eei) | |
682 | { | |
683 | Output_section* dummy; | |
684 | uint64_t ret = this->arg_value(eei, &dummy); | |
685 | // Force the value to be absolute. | |
686 | *eei->result_section_pointer = NULL; | |
687 | return ret; | |
688 | } | |
689 | ||
690 | void | |
691 | print(FILE* f) const | |
692 | { | |
693 | fprintf(f, "ABSOLUTE("); | |
694 | this->arg_print(f); | |
695 | fprintf(f, ")"); | |
696 | } | |
697 | }; | |
698 | ||
699 | extern "C" Expression* | |
700 | script_exp_function_absolute(Expression* arg) | |
701 | { | |
702 | return new Absolute_expression(arg); | |
703 | } | |
704 | ||
705 | // ALIGN function. | |
e5756efb ILT |
706 | |
707 | class Align_expression : public Binary_expression | |
708 | { | |
709 | public: | |
710 | Align_expression(Expression* left, Expression* right) | |
711 | : Binary_expression(left, right) | |
712 | { } | |
713 | ||
714 | uint64_t | |
715 | value(const Expression_eval_info* eei) | |
716 | { | |
77e65537 ILT |
717 | Output_section* align_section; |
718 | uint64_t align = this->right_value(eei, &align_section); | |
719 | if (align_section != NULL | |
8851ecca | 720 | && parameters->options().relocatable()) |
77e65537 ILT |
721 | gold_warning(_("aligning to section relative value")); |
722 | ||
723 | uint64_t value = this->left_value(eei, eei->result_section_pointer); | |
e5756efb ILT |
724 | if (align <= 1) |
725 | return value; | |
726 | return ((value + align - 1) / align) * align; | |
727 | } | |
494e05f4 ILT |
728 | |
729 | void | |
730 | print(FILE* f) const | |
731 | { this->print_function(f, "ALIGN"); } | |
e5756efb ILT |
732 | }; |
733 | ||
734 | extern "C" Expression* | |
735 | script_exp_function_align(Expression* left, Expression* right) | |
736 | { | |
737 | return new Align_expression(left, right); | |
738 | } | |
739 | ||
3edc73f2 | 740 | // ASSERT function. |
e5756efb ILT |
741 | |
742 | class Assert_expression : public Unary_expression | |
743 | { | |
744 | public: | |
745 | Assert_expression(Expression* arg, const char* message, size_t length) | |
746 | : Unary_expression(arg), message_(message, length) | |
747 | { } | |
748 | ||
749 | uint64_t | |
750 | value(const Expression_eval_info* eei) | |
751 | { | |
77e65537 | 752 | uint64_t value = this->arg_value(eei, eei->result_section_pointer); |
919ed24c | 753 | if (!value && eei->check_assertions) |
e5756efb ILT |
754 | gold_error("%s", this->message_.c_str()); |
755 | return value; | |
756 | } | |
757 | ||
494e05f4 ILT |
758 | void |
759 | print(FILE* f) const | |
760 | { | |
761 | fprintf(f, "ASSERT("); | |
762 | this->arg_print(f); | |
763 | fprintf(f, ", %s)", this->message_.c_str()); | |
764 | } | |
765 | ||
e5756efb ILT |
766 | private: |
767 | std::string message_; | |
768 | }; | |
769 | ||
770 | extern "C" Expression* | |
771 | script_exp_function_assert(Expression* expr, const char* message, | |
772 | size_t length) | |
773 | { | |
774 | return new Assert_expression(expr, message, length); | |
775 | } | |
776 | ||
7508a093 | 777 | // ADDR function. |
494e05f4 | 778 | |
7508a093 | 779 | class Addr_expression : public Section_expression |
494e05f4 ILT |
780 | { |
781 | public: | |
782 | Addr_expression(const char* section_name, size_t section_name_len) | |
7508a093 | 783 | : Section_expression(section_name, section_name_len) |
494e05f4 ILT |
784 | { } |
785 | ||
7508a093 | 786 | protected: |
494e05f4 | 787 | uint64_t |
3edc73f2 | 788 | value_from_output_section(const Expression_eval_info* eei, |
7508a093 ILT |
789 | Output_section* os) |
790 | { | |
791 | *eei->result_section_pointer = os; | |
792 | return os->address(); | |
793 | } | |
494e05f4 | 794 | |
7508a093 ILT |
795 | const char* |
796 | function_name() const | |
797 | { return "ADDR"; } | |
494e05f4 ILT |
798 | }; |
799 | ||
494e05f4 ILT |
800 | extern "C" Expression* |
801 | script_exp_function_addr(const char* section_name, size_t section_name_len) | |
802 | { | |
803 | return new Addr_expression(section_name, section_name_len); | |
804 | } | |
805 | ||
3edc73f2 ILT |
806 | // ALIGNOF. |
807 | ||
808 | class Alignof_expression : public Section_expression | |
809 | { | |
810 | public: | |
811 | Alignof_expression(const char* section_name, size_t section_name_len) | |
812 | : Section_expression(section_name, section_name_len) | |
813 | { } | |
814 | ||
815 | protected: | |
816 | uint64_t | |
817 | value_from_output_section(const Expression_eval_info*, | |
818 | Output_section* os) | |
819 | { return os->addralign(); } | |
820 | ||
821 | const char* | |
822 | function_name() const | |
823 | { return "ALIGNOF"; } | |
824 | }; | |
825 | ||
826 | extern "C" Expression* | |
827 | script_exp_function_alignof(const char* section_name, size_t section_name_len) | |
828 | { | |
829 | return new Alignof_expression(section_name, section_name_len); | |
830 | } | |
831 | ||
3802b2dd ILT |
832 | // CONSTANT. It would be nice if we could simply evaluate this |
833 | // immediately and return an Integer_expression, but unfortunately we | |
834 | // don't know the target. | |
835 | ||
836 | class Constant_expression : public Expression | |
837 | { | |
838 | public: | |
839 | Constant_expression(const char* name, size_t length); | |
840 | ||
841 | uint64_t | |
842 | value(const Expression_eval_info*); | |
843 | ||
844 | void | |
845 | print(FILE* f) const; | |
846 | ||
847 | private: | |
848 | enum Constant_function | |
849 | { | |
850 | CONSTANT_MAXPAGESIZE, | |
851 | CONSTANT_COMMONPAGESIZE | |
852 | }; | |
e5756efb | 853 | |
3802b2dd ILT |
854 | Constant_function function_; |
855 | }; | |
856 | ||
857 | Constant_expression::Constant_expression(const char* name, size_t length) | |
858 | { | |
859 | if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) | |
860 | this->function_ = CONSTANT_MAXPAGESIZE; | |
861 | else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) | |
862 | this->function_ = CONSTANT_COMMONPAGESIZE; | |
863 | else | |
864 | { | |
865 | std::string s(name, length); | |
866 | gold_error(_("unknown constant %s"), s.c_str()); | |
867 | this->function_ = CONSTANT_MAXPAGESIZE; | |
868 | } | |
869 | } | |
870 | ||
871 | uint64_t | |
872 | Constant_expression::value(const Expression_eval_info*) | |
873 | { | |
874 | switch (this->function_) | |
875 | { | |
876 | case CONSTANT_MAXPAGESIZE: | |
8851ecca | 877 | return parameters->target().abi_pagesize(); |
3802b2dd | 878 | case CONSTANT_COMMONPAGESIZE: |
8851ecca | 879 | return parameters->target().common_pagesize(); |
3802b2dd ILT |
880 | default: |
881 | gold_unreachable(); | |
882 | } | |
883 | } | |
884 | ||
885 | void | |
886 | Constant_expression::print(FILE* f) const | |
887 | { | |
888 | const char* name; | |
889 | switch (this->function_) | |
890 | { | |
891 | case CONSTANT_MAXPAGESIZE: | |
892 | name = "MAXPAGESIZE"; | |
893 | break; | |
894 | case CONSTANT_COMMONPAGESIZE: | |
895 | name = "COMMONPAGESIZE"; | |
896 | break; | |
897 | default: | |
898 | gold_unreachable(); | |
899 | } | |
900 | fprintf(f, "CONSTANT(%s)", name); | |
901 | } | |
902 | ||
e5756efb | 903 | extern "C" Expression* |
3802b2dd | 904 | script_exp_function_constant(const char* name, size_t length) |
e5756efb | 905 | { |
3802b2dd | 906 | return new Constant_expression(name, length); |
e5756efb ILT |
907 | } |
908 | ||
3802b2dd ILT |
909 | // DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall |
910 | // back to the general case. | |
911 | ||
e5756efb | 912 | extern "C" Expression* |
3802b2dd | 913 | script_exp_function_data_segment_align(Expression* left, Expression*) |
e5756efb | 914 | { |
3802b2dd ILT |
915 | Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); |
916 | Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); | |
917 | Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), | |
918 | e2); | |
919 | return script_exp_binary_add(e1, e3); | |
e5756efb ILT |
920 | } |
921 | ||
3802b2dd ILT |
922 | // DATA_SEGMENT_RELRO. FIXME: This is not implemented. |
923 | ||
e5756efb | 924 | extern "C" Expression* |
3802b2dd | 925 | script_exp_function_data_segment_relro_end(Expression*, Expression* right) |
e5756efb | 926 | { |
3802b2dd | 927 | return right; |
e5756efb ILT |
928 | } |
929 | ||
3802b2dd ILT |
930 | // DATA_SEGMENT_END. FIXME: This is not implemented. |
931 | ||
e5756efb | 932 | extern "C" Expression* |
3802b2dd | 933 | script_exp_function_data_segment_end(Expression* val) |
e5756efb | 934 | { |
3802b2dd ILT |
935 | return val; |
936 | } | |
937 | ||
3edc73f2 ILT |
938 | // DEFINED function. |
939 | ||
940 | class Defined_expression : public Expression | |
941 | { | |
942 | public: | |
943 | Defined_expression(const char* symbol_name, size_t symbol_name_len) | |
944 | : symbol_name_(symbol_name, symbol_name_len) | |
945 | { } | |
946 | ||
947 | uint64_t | |
948 | value(const Expression_eval_info* eei) | |
949 | { | |
950 | Symbol* sym = eei->symtab->lookup(this->symbol_name_.c_str()); | |
951 | return sym != NULL && sym->is_defined(); | |
952 | } | |
953 | ||
954 | void | |
955 | print(FILE* f) const | |
956 | { fprintf(f, "DEFINED(%s)", this->symbol_name_.c_str()); } | |
957 | ||
958 | private: | |
959 | std::string symbol_name_; | |
960 | }; | |
961 | ||
962 | extern "C" Expression* | |
963 | script_exp_function_defined(const char* symbol_name, size_t symbol_name_len) | |
964 | { | |
965 | return new Defined_expression(symbol_name, symbol_name_len); | |
966 | } | |
967 | ||
7508a093 ILT |
968 | // LOADADDR function |
969 | ||
970 | class Loadaddr_expression : public Section_expression | |
971 | { | |
972 | public: | |
973 | Loadaddr_expression(const char* section_name, size_t section_name_len) | |
974 | : Section_expression(section_name, section_name_len) | |
975 | { } | |
976 | ||
977 | protected: | |
978 | uint64_t | |
3edc73f2 | 979 | value_from_output_section(const Expression_eval_info* eei, |
7508a093 ILT |
980 | Output_section* os) |
981 | { | |
982 | if (os->has_load_address()) | |
983 | return os->load_address(); | |
984 | else | |
985 | { | |
986 | *eei->result_section_pointer = os; | |
987 | return os->address(); | |
988 | } | |
989 | } | |
990 | ||
991 | const char* | |
992 | function_name() const | |
993 | { return "LOADADDR"; } | |
994 | }; | |
995 | ||
996 | extern "C" Expression* | |
997 | script_exp_function_loadaddr(const char* section_name, size_t section_name_len) | |
998 | { | |
999 | return new Loadaddr_expression(section_name, section_name_len); | |
1000 | } | |
1001 | ||
1002 | // SIZEOF function | |
1003 | ||
1004 | class Sizeof_expression : public Section_expression | |
1005 | { | |
1006 | public: | |
1007 | Sizeof_expression(const char* section_name, size_t section_name_len) | |
1008 | : Section_expression(section_name, section_name_len) | |
1009 | { } | |
1010 | ||
1011 | protected: | |
1012 | uint64_t | |
3edc73f2 | 1013 | value_from_output_section(const Expression_eval_info*, |
7508a093 ILT |
1014 | Output_section* os) |
1015 | { | |
1016 | // We can not use data_size here, as the size of the section may | |
1017 | // not have been finalized. Instead we get whatever the current | |
1018 | // size is. This will work correctly for backward references in | |
1019 | // linker scripts. | |
1020 | return os->current_data_size(); | |
1021 | } | |
1022 | ||
1023 | const char* | |
1024 | function_name() const | |
1025 | { return "SIZEOF"; } | |
1026 | }; | |
1027 | ||
1028 | extern "C" Expression* | |
1029 | script_exp_function_sizeof(const char* section_name, size_t section_name_len) | |
1030 | { | |
1031 | return new Sizeof_expression(section_name, section_name_len); | |
1032 | } | |
1033 | ||
3802b2dd ILT |
1034 | // SIZEOF_HEADERS. |
1035 | ||
1036 | class Sizeof_headers_expression : public Expression | |
1037 | { | |
1038 | public: | |
1039 | Sizeof_headers_expression() | |
1040 | { } | |
1041 | ||
1042 | uint64_t | |
1043 | value(const Expression_eval_info*); | |
1044 | ||
1045 | void | |
1046 | print(FILE* f) const | |
1047 | { fprintf(f, "SIZEOF_HEADERS"); } | |
1048 | }; | |
1049 | ||
1050 | uint64_t | |
1051 | Sizeof_headers_expression::value(const Expression_eval_info* eei) | |
1052 | { | |
1053 | unsigned int ehdr_size; | |
1054 | unsigned int phdr_size; | |
8851ecca | 1055 | if (parameters->target().get_size() == 32) |
3802b2dd ILT |
1056 | { |
1057 | ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; | |
1058 | phdr_size = elfcpp::Elf_sizes<32>::phdr_size; | |
1059 | } | |
8851ecca | 1060 | else if (parameters->target().get_size() == 64) |
3802b2dd ILT |
1061 | { |
1062 | ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; | |
1063 | phdr_size = elfcpp::Elf_sizes<64>::phdr_size; | |
1064 | } | |
1065 | else | |
1066 | gold_unreachable(); | |
1067 | ||
1068 | return ehdr_size + phdr_size * eei->layout->expected_segment_count(); | |
e5756efb ILT |
1069 | } |
1070 | ||
e5756efb | 1071 | extern "C" Expression* |
3802b2dd | 1072 | script_exp_function_sizeof_headers() |
e5756efb | 1073 | { |
3802b2dd | 1074 | return new Sizeof_headers_expression(); |
e5756efb ILT |
1075 | } |
1076 | ||
3edc73f2 ILT |
1077 | // In the GNU linker SEGMENT_START basically returns the value for |
1078 | // -Ttext, -Tdata, or -Tbss. We could implement this by copying the | |
1079 | // values from General_options to Parameters. But I doubt that | |
1080 | // anybody actually uses it. The point of it for the GNU linker was | |
1081 | // because -Ttext set the address of the .text section rather than the | |
1082 | // text segment. In gold -Ttext sets the text segment address anyhow. | |
3802b2dd | 1083 | |
e5756efb | 1084 | extern "C" Expression* |
3edc73f2 | 1085 | script_exp_function_segment_start(const char*, size_t, Expression*) |
e5756efb | 1086 | { |
3edc73f2 | 1087 | gold_fatal(_("SEGMENT_START not implemented")); |
e5756efb ILT |
1088 | } |
1089 | ||
3edc73f2 ILT |
1090 | // Functions for memory regions. These can not be implemented unless |
1091 | // and until we implement memory regions. | |
e5756efb | 1092 | |
e5756efb | 1093 | extern "C" Expression* |
3802b2dd | 1094 | script_exp_function_origin(const char*, size_t) |
e5756efb | 1095 | { |
3802b2dd | 1096 | gold_fatal(_("ORIGIN not implemented")); |
e5756efb ILT |
1097 | } |
1098 | ||
1099 | extern "C" Expression* | |
3802b2dd | 1100 | script_exp_function_length(const char*, size_t) |
e5756efb | 1101 | { |
3802b2dd | 1102 | gold_fatal(_("LENGTH not implemented")); |
e5756efb ILT |
1103 | } |
1104 | ||
e5756efb | 1105 | } // End namespace gold. |