]>
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 <[email protected]>. | |
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; |
a445fddf ILT |
57 | // Whether expressions can refer to the dot symbol. The dot symbol |
58 | // is only available within a SECTIONS clause. | |
59 | bool is_dot_available; | |
a445fddf ILT |
60 | // The current value of the dot symbol. |
61 | uint64_t dot_value; | |
77e65537 ILT |
62 | // The section in which the dot symbol is defined; this is NULL if |
63 | // it is absolute. | |
64 | Output_section* dot_section; | |
65 | // Points to where the section of the result should be stored. | |
66 | Output_section** result_section_pointer; | |
e5756efb ILT |
67 | }; |
68 | ||
69 | // Evaluate an expression. | |
70 | ||
71 | uint64_t | |
72 | Expression::eval(const Symbol_table* symtab, const Layout* layout) | |
a445fddf | 73 | { |
77e65537 ILT |
74 | Output_section* dummy; |
75 | return this->eval_maybe_dot(symtab, layout, false, 0, NULL, &dummy); | |
a445fddf ILT |
76 | } |
77 | ||
78 | // Evaluate an expression which may refer to the dot symbol. | |
79 | ||
80 | uint64_t | |
81 | Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, | |
77e65537 ILT |
82 | uint64_t dot_value, Output_section* dot_section, |
83 | Output_section** result_section_pointer) | |
a445fddf | 84 | { |
77e65537 ILT |
85 | return this->eval_maybe_dot(symtab, layout, true, dot_value, dot_section, |
86 | result_section_pointer); | |
a445fddf ILT |
87 | } |
88 | ||
89 | // Evaluate an expression which may or may not refer to the dot | |
90 | // symbol. | |
91 | ||
92 | uint64_t | |
93 | Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, | |
77e65537 ILT |
94 | bool is_dot_available, uint64_t dot_value, |
95 | Output_section* dot_section, | |
96 | Output_section** result_section_pointer) | |
e5756efb ILT |
97 | { |
98 | Expression_eval_info eei; | |
99 | eei.symtab = symtab; | |
100 | eei.layout = layout; | |
a445fddf | 101 | eei.is_dot_available = is_dot_available; |
a445fddf | 102 | eei.dot_value = dot_value; |
77e65537 | 103 | eei.dot_section = dot_section; |
a445fddf | 104 | |
77e65537 ILT |
105 | // We assume the value is absolute, and only set this to a section |
106 | // if we find a section relative reference. | |
107 | *result_section_pointer = NULL; | |
108 | eei.result_section_pointer = result_section_pointer; | |
a445fddf | 109 | |
e5756efb ILT |
110 | return this->value(&eei); |
111 | } | |
112 | ||
113 | // A number. | |
114 | ||
115 | class Integer_expression : public Expression | |
116 | { | |
117 | public: | |
118 | Integer_expression(uint64_t val) | |
119 | : val_(val) | |
120 | { } | |
121 | ||
122 | uint64_t | |
123 | value(const Expression_eval_info*) | |
124 | { return this->val_; } | |
125 | ||
494e05f4 ILT |
126 | void |
127 | print(FILE* f) const | |
128 | { fprintf(f, "0x%llx", static_cast<unsigned long long>(this->val_)); } | |
129 | ||
e5756efb ILT |
130 | private: |
131 | uint64_t val_; | |
132 | }; | |
133 | ||
134 | extern "C" Expression* | |
135 | script_exp_integer(uint64_t val) | |
136 | { | |
137 | return new Integer_expression(val); | |
138 | } | |
139 | ||
140 | // An expression whose value is the value of a symbol. | |
141 | ||
142 | class Symbol_expression : public Expression | |
143 | { | |
144 | public: | |
145 | Symbol_expression(const char* name, size_t length) | |
146 | : name_(name, length) | |
147 | { } | |
148 | ||
149 | uint64_t | |
150 | value(const Expression_eval_info*); | |
151 | ||
494e05f4 ILT |
152 | void |
153 | print(FILE* f) const | |
154 | { fprintf(f, "%s", this->name_.c_str()); } | |
155 | ||
e5756efb ILT |
156 | private: |
157 | std::string name_; | |
158 | }; | |
159 | ||
160 | uint64_t | |
161 | Symbol_expression::value(const Expression_eval_info* eei) | |
162 | { | |
163 | Symbol* sym = eei->symtab->lookup(this->name_.c_str()); | |
164 | if (sym == NULL || !sym->is_defined()) | |
165 | { | |
166 | gold_error(_("undefined symbol '%s' referenced in expression"), | |
167 | this->name_.c_str()); | |
168 | return 0; | |
169 | } | |
170 | ||
77e65537 | 171 | *eei->result_section_pointer = sym->output_section(); |
a445fddf | 172 | |
e5756efb ILT |
173 | if (parameters->get_size() == 32) |
174 | return eei->symtab->get_sized_symbol<32>(sym)->value(); | |
175 | else if (parameters->get_size() == 64) | |
176 | return eei->symtab->get_sized_symbol<64>(sym)->value(); | |
177 | else | |
178 | gold_unreachable(); | |
179 | } | |
180 | ||
181 | // An expression whose value is the value of the special symbol ".". | |
182 | // This is only valid within a SECTIONS clause. | |
183 | ||
184 | class Dot_expression : public Expression | |
185 | { | |
186 | public: | |
187 | Dot_expression() | |
188 | { } | |
189 | ||
190 | uint64_t | |
191 | value(const Expression_eval_info*); | |
494e05f4 ILT |
192 | |
193 | void | |
194 | print(FILE* f) const | |
195 | { fprintf(f, "."); } | |
e5756efb ILT |
196 | }; |
197 | ||
198 | uint64_t | |
a445fddf | 199 | Dot_expression::value(const Expression_eval_info* eei) |
e5756efb | 200 | { |
a445fddf ILT |
201 | if (!eei->is_dot_available) |
202 | { | |
203 | gold_error(_("invalid reference to dot symbol outside of " | |
204 | "SECTIONS clause")); | |
205 | return 0; | |
206 | } | |
77e65537 | 207 | *eei->result_section_pointer = eei->dot_section; |
a445fddf | 208 | return eei->dot_value; |
e5756efb ILT |
209 | } |
210 | ||
211 | // A string. This is either the name of a symbol, or ".". | |
212 | ||
213 | extern "C" Expression* | |
214 | script_exp_string(const char* name, size_t length) | |
215 | { | |
216 | if (length == 1 && name[0] == '.') | |
217 | return new Dot_expression(); | |
218 | else | |
219 | return new Symbol_expression(name, length); | |
220 | } | |
221 | ||
222 | // A unary expression. | |
223 | ||
224 | class Unary_expression : public Expression | |
225 | { | |
226 | public: | |
227 | Unary_expression(Expression* arg) | |
228 | : arg_(arg) | |
229 | { } | |
230 | ||
231 | ~Unary_expression() | |
232 | { delete this->arg_; } | |
233 | ||
234 | protected: | |
235 | uint64_t | |
77e65537 ILT |
236 | arg_value(const Expression_eval_info* eei, |
237 | Output_section** arg_section_pointer) const | |
238 | { | |
239 | return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, | |
240 | eei->is_dot_available, | |
241 | eei->dot_value, | |
242 | eei->dot_section, | |
243 | arg_section_pointer); | |
244 | } | |
e5756efb | 245 | |
494e05f4 ILT |
246 | void |
247 | arg_print(FILE* f) const | |
248 | { this->arg_->print(f); } | |
249 | ||
e5756efb ILT |
250 | private: |
251 | Expression* arg_; | |
252 | }; | |
253 | ||
254 | // Handle unary operators. We use a preprocessor macro as a hack to | |
255 | // capture the C operator. | |
256 | ||
77e65537 ILT |
257 | #define UNARY_EXPRESSION(NAME, OPERATOR) \ |
258 | class Unary_ ## NAME : public Unary_expression \ | |
259 | { \ | |
260 | public: \ | |
261 | Unary_ ## NAME(Expression* arg) \ | |
262 | : Unary_expression(arg) \ | |
263 | { } \ | |
264 | \ | |
265 | uint64_t \ | |
266 | value(const Expression_eval_info* eei) \ | |
267 | { \ | |
268 | Output_section* arg_section; \ | |
269 | uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ | |
270 | if (arg_section != NULL && parameters->output_is_object()) \ | |
271 | gold_warning(_("unary " #NAME " applied to section " \ | |
272 | "relative value")); \ | |
273 | return ret; \ | |
274 | } \ | |
275 | \ | |
276 | void \ | |
277 | print(FILE* f) const \ | |
278 | { \ | |
279 | fprintf(f, "(%s ", #OPERATOR); \ | |
280 | this->arg_print(f); \ | |
281 | fprintf(f, ")"); \ | |
282 | } \ | |
283 | }; \ | |
284 | \ | |
285 | extern "C" Expression* \ | |
286 | script_exp_unary_ ## NAME(Expression* arg) \ | |
287 | { \ | |
288 | return new Unary_ ## NAME(arg); \ | |
e5756efb ILT |
289 | } |
290 | ||
291 | UNARY_EXPRESSION(minus, -) | |
292 | UNARY_EXPRESSION(logical_not, !) | |
293 | UNARY_EXPRESSION(bitwise_not, ~) | |
294 | ||
295 | // A binary expression. | |
296 | ||
297 | class Binary_expression : public Expression | |
298 | { | |
299 | public: | |
300 | Binary_expression(Expression* left, Expression* right) | |
301 | : left_(left), right_(right) | |
302 | { } | |
303 | ||
304 | ~Binary_expression() | |
305 | { | |
306 | delete this->left_; | |
307 | delete this->right_; | |
308 | } | |
309 | ||
310 | protected: | |
311 | uint64_t | |
77e65537 ILT |
312 | left_value(const Expression_eval_info* eei, |
313 | Output_section** section_pointer) const | |
314 | { | |
315 | return this->left_->eval_maybe_dot(eei->symtab, eei->layout, | |
316 | eei->is_dot_available, | |
317 | eei->dot_value, | |
318 | eei->dot_section, | |
319 | section_pointer); | |
320 | } | |
e5756efb ILT |
321 | |
322 | uint64_t | |
77e65537 ILT |
323 | right_value(const Expression_eval_info* eei, |
324 | Output_section** section_pointer) const | |
325 | { | |
326 | return this->right_->eval_maybe_dot(eei->symtab, eei->layout, | |
327 | eei->is_dot_available, | |
328 | eei->dot_value, | |
329 | eei->dot_section, | |
330 | section_pointer); | |
331 | } | |
e5756efb | 332 | |
494e05f4 ILT |
333 | void |
334 | left_print(FILE* f) const | |
335 | { this->left_->print(f); } | |
336 | ||
337 | void | |
338 | right_print(FILE* f) const | |
339 | { this->right_->print(f); } | |
340 | ||
341 | // This is a call to function FUNCTION_NAME. Print it. This is for | |
342 | // debugging. | |
343 | void | |
344 | print_function(FILE* f, const char *function_name) const | |
345 | { | |
346 | fprintf(f, "%s(", function_name); | |
347 | this->left_print(f); | |
348 | fprintf(f, ", "); | |
349 | this->right_print(f); | |
350 | fprintf(f, ")"); | |
351 | } | |
352 | ||
e5756efb ILT |
353 | private: |
354 | Expression* left_; | |
355 | Expression* right_; | |
356 | }; | |
357 | ||
358 | // Handle binary operators. We use a preprocessor macro as a hack to | |
77e65537 ILT |
359 | // capture the C operator. KEEP_LEFT means that if the left operand |
360 | // is section relative and the right operand is not, the result uses | |
361 | // the same section as the left operand. KEEP_RIGHT is the same with | |
362 | // left and right swapped. IS_DIV means that we need to give an error | |
363 | // if the right operand is zero. WARN means that we should warn if | |
364 | // used on section relative values in a relocatable link. We always | |
365 | // warn if used on values in different sections in a relocatable link. | |
366 | ||
367 | #define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ | |
e5756efb ILT |
368 | class Binary_ ## NAME : public Binary_expression \ |
369 | { \ | |
370 | public: \ | |
371 | Binary_ ## NAME(Expression* left, Expression* right) \ | |
372 | : Binary_expression(left, right) \ | |
373 | { } \ | |
374 | \ | |
375 | uint64_t \ | |
376 | value(const Expression_eval_info* eei) \ | |
377 | { \ | |
77e65537 ILT |
378 | Output_section* left_section; \ |
379 | uint64_t left = this->left_value(eei, &left_section); \ | |
380 | Output_section* right_section; \ | |
381 | uint64_t right = this->right_value(eei, &right_section); \ | |
382 | if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ | |
383 | *eei->result_section_pointer = right_section; \ | |
384 | else if (KEEP_LEFT \ | |
385 | && left_section != NULL \ | |
386 | && right_section == NULL) \ | |
387 | *eei->result_section_pointer = left_section; \ | |
388 | else if ((WARN || left_section != right_section) \ | |
389 | && (left_section != NULL || right_section != NULL) \ | |
390 | && parameters->output_is_object()) \ | |
391 | gold_warning(_("binary " #NAME " applied to section " \ | |
392 | "relative value")); \ | |
393 | if (IS_DIV && right == 0) \ | |
394 | { \ | |
395 | gold_error(_(#NAME " by zero")); \ | |
396 | return 0; \ | |
397 | } \ | |
398 | return left OPERATOR right; \ | |
494e05f4 ILT |
399 | } \ |
400 | \ | |
401 | void \ | |
402 | print(FILE* f) const \ | |
403 | { \ | |
404 | fprintf(f, "("); \ | |
405 | this->left_print(f); \ | |
406 | fprintf(f, " %s ", #OPERATOR); \ | |
407 | this->right_print(f); \ | |
408 | fprintf(f, ")"); \ | |
e5756efb ILT |
409 | } \ |
410 | }; \ | |
411 | \ | |
412 | extern "C" Expression* \ | |
413 | script_exp_binary_ ## NAME(Expression* left, Expression* right) \ | |
414 | { \ | |
415 | return new Binary_ ## NAME(left, right); \ | |
416 | } | |
417 | ||
77e65537 ILT |
418 | BINARY_EXPRESSION(mult, *, false, false, false, true) |
419 | BINARY_EXPRESSION(div, /, false, false, true, true) | |
420 | BINARY_EXPRESSION(mod, %, false, false, true, true) | |
421 | BINARY_EXPRESSION(add, +, true, true, false, true) | |
422 | BINARY_EXPRESSION(sub, -, true, false, false, false) | |
423 | BINARY_EXPRESSION(lshift, <<, false, false, false, true) | |
424 | BINARY_EXPRESSION(rshift, >>, false, false, false, true) | |
425 | BINARY_EXPRESSION(eq, ==, false, false, false, false) | |
426 | BINARY_EXPRESSION(ne, !=, false, false, false, false) | |
427 | BINARY_EXPRESSION(le, <=, false, false, false, false) | |
428 | BINARY_EXPRESSION(ge, >=, false, false, false, false) | |
429 | BINARY_EXPRESSION(lt, <, false, false, false, false) | |
430 | BINARY_EXPRESSION(gt, >, false, false, false, false) | |
431 | BINARY_EXPRESSION(bitwise_and, &, true, true, false, true) | |
432 | BINARY_EXPRESSION(bitwise_xor, ^, true, true, false, true) | |
433 | BINARY_EXPRESSION(bitwise_or, |, true, true, false, true) | |
434 | BINARY_EXPRESSION(logical_and, &&, false, false, false, true) | |
435 | BINARY_EXPRESSION(logical_or, ||, false, false, false, true) | |
e5756efb ILT |
436 | |
437 | // A trinary expression. | |
438 | ||
439 | class Trinary_expression : public Expression | |
440 | { | |
441 | public: | |
442 | Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3) | |
443 | : arg1_(arg1), arg2_(arg2), arg3_(arg3) | |
444 | { } | |
445 | ||
446 | ~Trinary_expression() | |
447 | { | |
448 | delete this->arg1_; | |
449 | delete this->arg2_; | |
450 | delete this->arg3_; | |
451 | } | |
452 | ||
453 | protected: | |
454 | uint64_t | |
77e65537 ILT |
455 | arg1_value(const Expression_eval_info* eei, |
456 | Output_section** section_pointer) const | |
457 | { | |
458 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
459 | eei->is_dot_available, | |
460 | eei->dot_value, | |
461 | eei->dot_section, | |
462 | section_pointer); | |
463 | } | |
e5756efb ILT |
464 | |
465 | uint64_t | |
77e65537 ILT |
466 | arg2_value(const Expression_eval_info* eei, |
467 | Output_section** section_pointer) const | |
468 | { | |
469 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
470 | eei->is_dot_available, | |
471 | eei->dot_value, | |
472 | eei->dot_section, | |
473 | section_pointer); | |
474 | } | |
e5756efb ILT |
475 | |
476 | uint64_t | |
77e65537 ILT |
477 | arg3_value(const Expression_eval_info* eei, |
478 | Output_section** section_pointer) const | |
479 | { | |
480 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
481 | eei->is_dot_available, | |
482 | eei->dot_value, | |
483 | eei->dot_section, | |
484 | section_pointer); | |
485 | } | |
e5756efb | 486 | |
494e05f4 ILT |
487 | void |
488 | arg1_print(FILE* f) const | |
489 | { this->arg1_->print(f); } | |
490 | ||
491 | void | |
492 | arg2_print(FILE* f) const | |
493 | { this->arg2_->print(f); } | |
494 | ||
495 | void | |
496 | arg3_print(FILE* f) const | |
497 | { this->arg3_->print(f); } | |
498 | ||
e5756efb ILT |
499 | private: |
500 | Expression* arg1_; | |
501 | Expression* arg2_; | |
502 | Expression* arg3_; | |
503 | }; | |
504 | ||
505 | // The conditional operator. | |
506 | ||
507 | class Trinary_cond : public Trinary_expression | |
508 | { | |
509 | public: | |
510 | Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
511 | : Trinary_expression(arg1, arg2, arg3) | |
512 | { } | |
513 | ||
514 | uint64_t | |
515 | value(const Expression_eval_info* eei) | |
516 | { | |
77e65537 ILT |
517 | Output_section* arg1_section; |
518 | uint64_t arg1 = this->arg1_value(eei, &arg1_section); | |
519 | return (arg1 | |
520 | ? this->arg2_value(eei, eei->result_section_pointer) | |
521 | : this->arg3_value(eei, eei->result_section_pointer)); | |
e5756efb | 522 | } |
494e05f4 ILT |
523 | |
524 | void | |
525 | print(FILE* f) const | |
526 | { | |
527 | fprintf(f, "("); | |
528 | this->arg1_print(f); | |
529 | fprintf(f, " ? "); | |
530 | this->arg2_print(f); | |
531 | fprintf(f, " : "); | |
532 | this->arg3_print(f); | |
533 | fprintf(f, ")"); | |
534 | } | |
e5756efb ILT |
535 | }; |
536 | ||
537 | extern "C" Expression* | |
538 | script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
539 | { | |
540 | return new Trinary_cond(arg1, arg2, arg3); | |
541 | } | |
542 | ||
543 | // Max function. | |
544 | ||
545 | class Max_expression : public Binary_expression | |
546 | { | |
547 | public: | |
548 | Max_expression(Expression* left, Expression* right) | |
549 | : Binary_expression(left, right) | |
550 | { } | |
551 | ||
552 | uint64_t | |
553 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
554 | { |
555 | Output_section* left_section; | |
556 | uint64_t left = this->left_value(eei, &left_section); | |
557 | Output_section* right_section; | |
558 | uint64_t right = this->right_value(eei, &right_section); | |
559 | if (left_section == right_section) | |
560 | *eei->result_section_pointer = left_section; | |
561 | else if ((left_section != NULL || right_section != NULL) | |
562 | && parameters->output_is_object()) | |
563 | gold_warning(_("max applied to section relative value")); | |
564 | return std::max(left, right); | |
565 | } | |
494e05f4 ILT |
566 | |
567 | void | |
568 | print(FILE* f) const | |
569 | { this->print_function(f, "MAX"); } | |
e5756efb ILT |
570 | }; |
571 | ||
572 | extern "C" Expression* | |
573 | script_exp_function_max(Expression* left, Expression* right) | |
574 | { | |
575 | return new Max_expression(left, right); | |
576 | } | |
577 | ||
578 | // Min function. | |
579 | ||
580 | class Min_expression : public Binary_expression | |
581 | { | |
582 | public: | |
583 | Min_expression(Expression* left, Expression* right) | |
584 | : Binary_expression(left, right) | |
585 | { } | |
586 | ||
587 | uint64_t | |
588 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
589 | { |
590 | Output_section* left_section; | |
591 | uint64_t left = this->left_value(eei, &left_section); | |
592 | Output_section* right_section; | |
593 | uint64_t right = this->right_value(eei, &right_section); | |
594 | if (left_section == right_section) | |
595 | *eei->result_section_pointer = left_section; | |
596 | else if ((left_section != NULL || right_section != NULL) | |
597 | && parameters->output_is_object()) | |
598 | gold_warning(_("min applied to section relative value")); | |
599 | return std::min(left, right); | |
600 | } | |
494e05f4 ILT |
601 | |
602 | void | |
603 | print(FILE* f) const | |
604 | { this->print_function(f, "MIN"); } | |
e5756efb ILT |
605 | }; |
606 | ||
607 | extern "C" Expression* | |
608 | script_exp_function_min(Expression* left, Expression* right) | |
609 | { | |
610 | return new Min_expression(left, right); | |
611 | } | |
612 | ||
613 | // Align function. | |
614 | ||
615 | class Align_expression : public Binary_expression | |
616 | { | |
617 | public: | |
618 | Align_expression(Expression* left, Expression* right) | |
619 | : Binary_expression(left, right) | |
620 | { } | |
621 | ||
622 | uint64_t | |
623 | value(const Expression_eval_info* eei) | |
624 | { | |
77e65537 ILT |
625 | Output_section* align_section; |
626 | uint64_t align = this->right_value(eei, &align_section); | |
627 | if (align_section != NULL | |
628 | && parameters->output_is_object()) | |
629 | gold_warning(_("aligning to section relative value")); | |
630 | ||
631 | uint64_t value = this->left_value(eei, eei->result_section_pointer); | |
e5756efb ILT |
632 | if (align <= 1) |
633 | return value; | |
634 | return ((value + align - 1) / align) * align; | |
635 | } | |
494e05f4 ILT |
636 | |
637 | void | |
638 | print(FILE* f) const | |
639 | { this->print_function(f, "ALIGN"); } | |
e5756efb ILT |
640 | }; |
641 | ||
642 | extern "C" Expression* | |
643 | script_exp_function_align(Expression* left, Expression* right) | |
644 | { | |
645 | return new Align_expression(left, right); | |
646 | } | |
647 | ||
648 | // Assert function. | |
649 | ||
650 | class Assert_expression : public Unary_expression | |
651 | { | |
652 | public: | |
653 | Assert_expression(Expression* arg, const char* message, size_t length) | |
654 | : Unary_expression(arg), message_(message, length) | |
655 | { } | |
656 | ||
657 | uint64_t | |
658 | value(const Expression_eval_info* eei) | |
659 | { | |
77e65537 | 660 | uint64_t value = this->arg_value(eei, eei->result_section_pointer); |
e5756efb ILT |
661 | if (!value) |
662 | gold_error("%s", this->message_.c_str()); | |
663 | return value; | |
664 | } | |
665 | ||
494e05f4 ILT |
666 | void |
667 | print(FILE* f) const | |
668 | { | |
669 | fprintf(f, "ASSERT("); | |
670 | this->arg_print(f); | |
671 | fprintf(f, ", %s)", this->message_.c_str()); | |
672 | } | |
673 | ||
e5756efb ILT |
674 | private: |
675 | std::string message_; | |
676 | }; | |
677 | ||
678 | extern "C" Expression* | |
679 | script_exp_function_assert(Expression* expr, const char* message, | |
680 | size_t length) | |
681 | { | |
682 | return new Assert_expression(expr, message, length); | |
683 | } | |
684 | ||
494e05f4 ILT |
685 | // Addr function. |
686 | ||
687 | class Addr_expression : public Expression | |
688 | { | |
689 | public: | |
690 | Addr_expression(const char* section_name, size_t section_name_len) | |
691 | : section_name_(section_name, section_name_len) | |
692 | { } | |
693 | ||
694 | uint64_t | |
695 | value(const Expression_eval_info*); | |
696 | ||
697 | void | |
698 | print(FILE* f) const | |
699 | { fprintf(f, "ADDR(%s)", this->section_name_.c_str()); } | |
700 | ||
701 | private: | |
702 | std::string section_name_; | |
703 | }; | |
704 | ||
705 | uint64_t | |
706 | Addr_expression::value(const Expression_eval_info* eei) | |
707 | { | |
708 | const char* section_name = this->section_name_.c_str(); | |
709 | Output_section* os = eei->layout->find_output_section(section_name); | |
710 | if (os == NULL) | |
711 | { | |
712 | gold_error("ADDR called on nonexistent output section '%s'", | |
713 | section_name); | |
714 | return 0; | |
715 | } | |
a445fddf | 716 | |
77e65537 | 717 | *eei->result_section_pointer = os; |
a445fddf | 718 | |
494e05f4 ILT |
719 | return os->address(); |
720 | } | |
721 | ||
722 | extern "C" Expression* | |
723 | script_exp_function_addr(const char* section_name, size_t section_name_len) | |
724 | { | |
725 | return new Addr_expression(section_name, section_name_len); | |
726 | } | |
727 | ||
3802b2dd ILT |
728 | // CONSTANT. It would be nice if we could simply evaluate this |
729 | // immediately and return an Integer_expression, but unfortunately we | |
730 | // don't know the target. | |
731 | ||
732 | class Constant_expression : public Expression | |
733 | { | |
734 | public: | |
735 | Constant_expression(const char* name, size_t length); | |
736 | ||
737 | uint64_t | |
738 | value(const Expression_eval_info*); | |
739 | ||
740 | void | |
741 | print(FILE* f) const; | |
742 | ||
743 | private: | |
744 | enum Constant_function | |
745 | { | |
746 | CONSTANT_MAXPAGESIZE, | |
747 | CONSTANT_COMMONPAGESIZE | |
748 | }; | |
e5756efb | 749 | |
3802b2dd ILT |
750 | Constant_function function_; |
751 | }; | |
752 | ||
753 | Constant_expression::Constant_expression(const char* name, size_t length) | |
754 | { | |
755 | if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) | |
756 | this->function_ = CONSTANT_MAXPAGESIZE; | |
757 | else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) | |
758 | this->function_ = CONSTANT_COMMONPAGESIZE; | |
759 | else | |
760 | { | |
761 | std::string s(name, length); | |
762 | gold_error(_("unknown constant %s"), s.c_str()); | |
763 | this->function_ = CONSTANT_MAXPAGESIZE; | |
764 | } | |
765 | } | |
766 | ||
767 | uint64_t | |
768 | Constant_expression::value(const Expression_eval_info*) | |
769 | { | |
770 | switch (this->function_) | |
771 | { | |
772 | case CONSTANT_MAXPAGESIZE: | |
773 | return parameters->target()->abi_pagesize(); | |
774 | case CONSTANT_COMMONPAGESIZE: | |
775 | return parameters->target()->common_pagesize(); | |
776 | default: | |
777 | gold_unreachable(); | |
778 | } | |
779 | } | |
780 | ||
781 | void | |
782 | Constant_expression::print(FILE* f) const | |
783 | { | |
784 | const char* name; | |
785 | switch (this->function_) | |
786 | { | |
787 | case CONSTANT_MAXPAGESIZE: | |
788 | name = "MAXPAGESIZE"; | |
789 | break; | |
790 | case CONSTANT_COMMONPAGESIZE: | |
791 | name = "COMMONPAGESIZE"; | |
792 | break; | |
793 | default: | |
794 | gold_unreachable(); | |
795 | } | |
796 | fprintf(f, "CONSTANT(%s)", name); | |
797 | } | |
798 | ||
e5756efb | 799 | extern "C" Expression* |
3802b2dd | 800 | script_exp_function_constant(const char* name, size_t length) |
e5756efb | 801 | { |
3802b2dd | 802 | return new Constant_expression(name, length); |
e5756efb ILT |
803 | } |
804 | ||
3802b2dd ILT |
805 | // DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall |
806 | // back to the general case. | |
807 | ||
e5756efb | 808 | extern "C" Expression* |
3802b2dd | 809 | script_exp_function_data_segment_align(Expression* left, Expression*) |
e5756efb | 810 | { |
3802b2dd ILT |
811 | Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); |
812 | Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); | |
813 | Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), | |
814 | e2); | |
815 | return script_exp_binary_add(e1, e3); | |
e5756efb ILT |
816 | } |
817 | ||
3802b2dd ILT |
818 | // DATA_SEGMENT_RELRO. FIXME: This is not implemented. |
819 | ||
e5756efb | 820 | extern "C" Expression* |
3802b2dd | 821 | script_exp_function_data_segment_relro_end(Expression*, Expression* right) |
e5756efb | 822 | { |
3802b2dd | 823 | return right; |
e5756efb ILT |
824 | } |
825 | ||
3802b2dd ILT |
826 | // DATA_SEGMENT_END. FIXME: This is not implemented. |
827 | ||
e5756efb | 828 | extern "C" Expression* |
3802b2dd | 829 | script_exp_function_data_segment_end(Expression* val) |
e5756efb | 830 | { |
3802b2dd ILT |
831 | return val; |
832 | } | |
833 | ||
834 | // SIZEOF_HEADERS. | |
835 | ||
836 | class Sizeof_headers_expression : public Expression | |
837 | { | |
838 | public: | |
839 | Sizeof_headers_expression() | |
840 | { } | |
841 | ||
842 | uint64_t | |
843 | value(const Expression_eval_info*); | |
844 | ||
845 | void | |
846 | print(FILE* f) const | |
847 | { fprintf(f, "SIZEOF_HEADERS"); } | |
848 | }; | |
849 | ||
850 | uint64_t | |
851 | Sizeof_headers_expression::value(const Expression_eval_info* eei) | |
852 | { | |
853 | unsigned int ehdr_size; | |
854 | unsigned int phdr_size; | |
855 | if (parameters->get_size() == 32) | |
856 | { | |
857 | ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; | |
858 | phdr_size = elfcpp::Elf_sizes<32>::phdr_size; | |
859 | } | |
860 | else if (parameters->get_size() == 64) | |
861 | { | |
862 | ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; | |
863 | phdr_size = elfcpp::Elf_sizes<64>::phdr_size; | |
864 | } | |
865 | else | |
866 | gold_unreachable(); | |
867 | ||
868 | return ehdr_size + phdr_size * eei->layout->expected_segment_count(); | |
e5756efb ILT |
869 | } |
870 | ||
e5756efb | 871 | extern "C" Expression* |
3802b2dd | 872 | script_exp_function_sizeof_headers() |
e5756efb | 873 | { |
3802b2dd | 874 | return new Sizeof_headers_expression(); |
e5756efb ILT |
875 | } |
876 | ||
3802b2dd ILT |
877 | // Functions. |
878 | ||
e5756efb | 879 | extern "C" Expression* |
3802b2dd | 880 | script_exp_function_defined(const char*, size_t) |
e5756efb | 881 | { |
3802b2dd | 882 | gold_fatal(_("DEFINED not implemented")); |
e5756efb ILT |
883 | } |
884 | ||
885 | extern "C" Expression* | |
3802b2dd | 886 | script_exp_function_alignof(const char*, size_t) |
e5756efb | 887 | { |
3802b2dd | 888 | gold_fatal(_("ALIGNOF not implemented")); |
e5756efb ILT |
889 | } |
890 | ||
891 | extern "C" Expression* | |
3802b2dd | 892 | script_exp_function_sizeof(const char*, size_t) |
e5756efb | 893 | { |
3802b2dd | 894 | gold_fatal(_("SIZEOF not implemented")); |
e5756efb ILT |
895 | } |
896 | ||
897 | extern "C" Expression* | |
3802b2dd | 898 | script_exp_function_loadaddr(const char*, size_t) |
e5756efb | 899 | { |
3802b2dd | 900 | gold_fatal(_("LOADADDR not implemented")); |
e5756efb ILT |
901 | } |
902 | ||
903 | extern "C" Expression* | |
3802b2dd | 904 | script_exp_function_origin(const char*, size_t) |
e5756efb | 905 | { |
3802b2dd | 906 | gold_fatal(_("ORIGIN not implemented")); |
e5756efb ILT |
907 | } |
908 | ||
909 | extern "C" Expression* | |
3802b2dd | 910 | script_exp_function_length(const char*, size_t) |
e5756efb | 911 | { |
3802b2dd | 912 | gold_fatal(_("LENGTH not implemented")); |
e5756efb ILT |
913 | } |
914 | ||
915 | extern "C" Expression* | |
3802b2dd | 916 | script_exp_function_absolute(Expression*) |
e5756efb | 917 | { |
3802b2dd | 918 | gold_fatal(_("ABSOLUTE not implemented")); |
e5756efb ILT |
919 | } |
920 | ||
921 | extern "C" Expression* | |
922 | script_exp_function_segment_start(const char*, size_t, Expression*) | |
923 | { | |
924 | gold_fatal(_("SEGMENT_START not implemented")); | |
925 | } | |
926 | ||
927 | } // End namespace gold. |