Commit | Line | Data |
---|---|---|
e5756efb ILT |
1 | // expression.cc -- expressions in linker scripts for gold |
2 | ||
219d1afa | 3 | // Copyright (C) 2006-2018 Free Software Foundation, Inc. |
e5756efb ILT |
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; | |
f6973bdc ILT |
69 | // Pointer to where the alignment of the result should be stored. |
70 | uint64_t* result_alignment_pointer; | |
e051745c CC |
71 | // Pointer to where the type of the symbol on the RHS should be stored. |
72 | elfcpp::STT* type_pointer; | |
73 | // Pointer to where the visibility of the symbol on the RHS should be stored. | |
74 | elfcpp::STV* vis_pointer; | |
75 | // Pointer to where the rest of the symbol's st_other field should be stored. | |
76 | unsigned char* nonvis_pointer; | |
1757d35c CC |
77 | // Whether the value is valid. In Symbol_assignment::set_if_absolute, we |
78 | // may be trying to evaluate the address of a section whose address is not | |
79 | // yet finalized, and we need to fail the evaluation gracefully. | |
80 | bool *is_valid_pointer; | |
e5756efb ILT |
81 | }; |
82 | ||
83 | // Evaluate an expression. | |
84 | ||
85 | uint64_t | |
919ed24c ILT |
86 | Expression::eval(const Symbol_table* symtab, const Layout* layout, |
87 | bool check_assertions) | |
a445fddf | 88 | { |
e051745c | 89 | return this->eval_maybe_dot(symtab, layout, check_assertions, false, 0, |
1757d35c | 90 | NULL, NULL, NULL, NULL, NULL, NULL, false, NULL); |
a445fddf ILT |
91 | } |
92 | ||
93 | // Evaluate an expression which may refer to the dot symbol. | |
94 | ||
95 | uint64_t | |
96 | Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, | |
919ed24c ILT |
97 | bool check_assertions, uint64_t dot_value, |
98 | Output_section* dot_section, | |
f6973bdc | 99 | Output_section** result_section_pointer, |
286adcf4 CC |
100 | uint64_t* result_alignment_pointer, |
101 | bool is_section_dot_assignment) | |
a445fddf | 102 | { |
919ed24c | 103 | return this->eval_maybe_dot(symtab, layout, check_assertions, true, |
f6973bdc | 104 | dot_value, dot_section, result_section_pointer, |
e051745c | 105 | result_alignment_pointer, NULL, NULL, NULL, |
1757d35c | 106 | is_section_dot_assignment, NULL); |
a445fddf ILT |
107 | } |
108 | ||
109 | // Evaluate an expression which may or may not refer to the dot | |
110 | // symbol. | |
111 | ||
112 | uint64_t | |
113 | Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, | |
919ed24c ILT |
114 | bool check_assertions, bool is_dot_available, |
115 | uint64_t dot_value, Output_section* dot_section, | |
f6973bdc | 116 | Output_section** result_section_pointer, |
286adcf4 | 117 | uint64_t* result_alignment_pointer, |
e051745c CC |
118 | elfcpp::STT* type_pointer, |
119 | elfcpp::STV* vis_pointer, | |
120 | unsigned char* nonvis_pointer, | |
1757d35c CC |
121 | bool is_section_dot_assignment, |
122 | bool* is_valid_pointer) | |
e5756efb ILT |
123 | { |
124 | Expression_eval_info eei; | |
125 | eei.symtab = symtab; | |
126 | eei.layout = layout; | |
919ed24c | 127 | eei.check_assertions = check_assertions; |
a445fddf | 128 | eei.is_dot_available = is_dot_available; |
a445fddf | 129 | eei.dot_value = dot_value; |
77e65537 | 130 | eei.dot_section = dot_section; |
a445fddf | 131 | |
77e65537 | 132 | // We assume the value is absolute, and only set this to a section |
286adcf4 | 133 | // if we find a section-relative reference. |
bacff3ab NC |
134 | if (result_section_pointer != NULL) |
135 | *result_section_pointer = NULL; | |
77e65537 | 136 | eei.result_section_pointer = result_section_pointer; |
a445fddf | 137 | |
e051745c CC |
138 | // For symbol=symbol assignments, we need to track the type, visibility, |
139 | // and remaining st_other bits. | |
140 | eei.type_pointer = type_pointer; | |
141 | eei.vis_pointer = vis_pointer; | |
142 | eei.nonvis_pointer = nonvis_pointer; | |
143 | ||
f6973bdc ILT |
144 | eei.result_alignment_pointer = result_alignment_pointer; |
145 | ||
1757d35c CC |
146 | // Assume the value is valid until we try to evaluate an expression |
147 | // that can't be evaluated yet. | |
148 | bool is_valid = true; | |
149 | eei.is_valid_pointer = &is_valid; | |
150 | ||
286adcf4 CC |
151 | uint64_t val = this->value(&eei); |
152 | ||
1757d35c CC |
153 | if (is_valid_pointer != NULL) |
154 | *is_valid_pointer = is_valid; | |
155 | else | |
156 | gold_assert(is_valid); | |
157 | ||
286adcf4 CC |
158 | // If this is an assignment to dot within a section, and the value |
159 | // is absolute, treat it as a section-relative offset. | |
160 | if (is_section_dot_assignment && *result_section_pointer == NULL) | |
161 | { | |
162 | gold_assert(dot_section != NULL); | |
163 | val += dot_section->address(); | |
164 | *result_section_pointer = dot_section; | |
165 | } | |
166 | return val; | |
e5756efb ILT |
167 | } |
168 | ||
169 | // A number. | |
170 | ||
171 | class Integer_expression : public Expression | |
172 | { | |
173 | public: | |
174 | Integer_expression(uint64_t val) | |
175 | : val_(val) | |
176 | { } | |
177 | ||
178 | uint64_t | |
179 | value(const Expression_eval_info*) | |
180 | { return this->val_; } | |
181 | ||
494e05f4 ILT |
182 | void |
183 | print(FILE* f) const | |
184 | { fprintf(f, "0x%llx", static_cast<unsigned long long>(this->val_)); } | |
185 | ||
e5756efb ILT |
186 | private: |
187 | uint64_t val_; | |
188 | }; | |
189 | ||
190 | extern "C" Expression* | |
191 | script_exp_integer(uint64_t val) | |
192 | { | |
193 | return new Integer_expression(val); | |
194 | } | |
195 | ||
196 | // An expression whose value is the value of a symbol. | |
197 | ||
198 | class Symbol_expression : public Expression | |
199 | { | |
200 | public: | |
201 | Symbol_expression(const char* name, size_t length) | |
202 | : name_(name, length) | |
203 | { } | |
204 | ||
205 | uint64_t | |
206 | value(const Expression_eval_info*); | |
207 | ||
3281b315 ST |
208 | void |
209 | set_expr_sym_in_real_elf(Symbol_table* symtab) const | |
210 | { | |
211 | Symbol* sym = symtab->lookup(this->name_.c_str()); | |
212 | if (sym != NULL) | |
213 | sym->set_in_real_elf(); | |
214 | } | |
215 | ||
494e05f4 ILT |
216 | void |
217 | print(FILE* f) const | |
218 | { fprintf(f, "%s", this->name_.c_str()); } | |
219 | ||
e5756efb ILT |
220 | private: |
221 | std::string name_; | |
222 | }; | |
223 | ||
224 | uint64_t | |
225 | Symbol_expression::value(const Expression_eval_info* eei) | |
226 | { | |
227 | Symbol* sym = eei->symtab->lookup(this->name_.c_str()); | |
228 | if (sym == NULL || !sym->is_defined()) | |
229 | { | |
230 | gold_error(_("undefined symbol '%s' referenced in expression"), | |
231 | this->name_.c_str()); | |
232 | return 0; | |
233 | } | |
234 | ||
bacff3ab NC |
235 | if (eei->result_section_pointer != NULL) |
236 | *eei->result_section_pointer = sym->output_section(); | |
e051745c CC |
237 | if (eei->type_pointer != NULL) |
238 | *eei->type_pointer = sym->type(); | |
239 | if (eei->vis_pointer != NULL) | |
240 | *eei->vis_pointer = sym->visibility(); | |
241 | if (eei->nonvis_pointer != NULL) | |
242 | *eei->nonvis_pointer = sym->nonvis(); | |
a445fddf | 243 | |
8851ecca | 244 | if (parameters->target().get_size() == 32) |
e5756efb | 245 | return eei->symtab->get_sized_symbol<32>(sym)->value(); |
8851ecca | 246 | else if (parameters->target().get_size() == 64) |
e5756efb ILT |
247 | return eei->symtab->get_sized_symbol<64>(sym)->value(); |
248 | else | |
249 | gold_unreachable(); | |
250 | } | |
251 | ||
252 | // An expression whose value is the value of the special symbol ".". | |
253 | // This is only valid within a SECTIONS clause. | |
254 | ||
255 | class Dot_expression : public Expression | |
256 | { | |
257 | public: | |
258 | Dot_expression() | |
259 | { } | |
260 | ||
261 | uint64_t | |
262 | value(const Expression_eval_info*); | |
494e05f4 ILT |
263 | |
264 | void | |
265 | print(FILE* f) const | |
266 | { fprintf(f, "."); } | |
e5756efb ILT |
267 | }; |
268 | ||
269 | uint64_t | |
a445fddf | 270 | Dot_expression::value(const Expression_eval_info* eei) |
e5756efb | 271 | { |
a445fddf ILT |
272 | if (!eei->is_dot_available) |
273 | { | |
274 | gold_error(_("invalid reference to dot symbol outside of " | |
275 | "SECTIONS clause")); | |
276 | return 0; | |
277 | } | |
bacff3ab NC |
278 | if (eei->result_section_pointer != NULL) |
279 | *eei->result_section_pointer = eei->dot_section; | |
a445fddf | 280 | return eei->dot_value; |
e5756efb ILT |
281 | } |
282 | ||
283 | // A string. This is either the name of a symbol, or ".". | |
284 | ||
285 | extern "C" Expression* | |
286 | script_exp_string(const char* name, size_t length) | |
287 | { | |
288 | if (length == 1 && name[0] == '.') | |
289 | return new Dot_expression(); | |
290 | else | |
291 | return new Symbol_expression(name, length); | |
292 | } | |
293 | ||
294 | // A unary expression. | |
295 | ||
296 | class Unary_expression : public Expression | |
297 | { | |
298 | public: | |
299 | Unary_expression(Expression* arg) | |
300 | : arg_(arg) | |
301 | { } | |
302 | ||
303 | ~Unary_expression() | |
304 | { delete this->arg_; } | |
305 | ||
306 | protected: | |
307 | uint64_t | |
77e65537 ILT |
308 | arg_value(const Expression_eval_info* eei, |
309 | Output_section** arg_section_pointer) const | |
310 | { | |
311 | return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 312 | eei->check_assertions, |
77e65537 ILT |
313 | eei->is_dot_available, |
314 | eei->dot_value, | |
315 | eei->dot_section, | |
f6973bdc | 316 | arg_section_pointer, |
286adcf4 | 317 | eei->result_alignment_pointer, |
e051745c CC |
318 | NULL, |
319 | NULL, | |
320 | NULL, | |
1757d35c CC |
321 | false, |
322 | eei->is_valid_pointer); | |
77e65537 | 323 | } |
e5756efb | 324 | |
494e05f4 ILT |
325 | void |
326 | arg_print(FILE* f) const | |
327 | { this->arg_->print(f); } | |
328 | ||
3281b315 ST |
329 | void |
330 | set_expr_sym_in_real_elf(Symbol_table* symtab) const | |
331 | { return this->arg_->set_expr_sym_in_real_elf(symtab); } | |
332 | ||
e5756efb ILT |
333 | private: |
334 | Expression* arg_; | |
335 | }; | |
336 | ||
337 | // Handle unary operators. We use a preprocessor macro as a hack to | |
338 | // capture the C operator. | |
339 | ||
77e65537 ILT |
340 | #define UNARY_EXPRESSION(NAME, OPERATOR) \ |
341 | class Unary_ ## NAME : public Unary_expression \ | |
342 | { \ | |
343 | public: \ | |
344 | Unary_ ## NAME(Expression* arg) \ | |
345 | : Unary_expression(arg) \ | |
346 | { } \ | |
347 | \ | |
348 | uint64_t \ | |
349 | value(const Expression_eval_info* eei) \ | |
350 | { \ | |
351 | Output_section* arg_section; \ | |
352 | uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ | |
8851ecca | 353 | if (arg_section != NULL && parameters->options().relocatable()) \ |
77e65537 ILT |
354 | gold_warning(_("unary " #NAME " applied to section " \ |
355 | "relative value")); \ | |
356 | return ret; \ | |
357 | } \ | |
358 | \ | |
359 | void \ | |
360 | print(FILE* f) const \ | |
361 | { \ | |
362 | fprintf(f, "(%s ", #OPERATOR); \ | |
363 | this->arg_print(f); \ | |
364 | fprintf(f, ")"); \ | |
365 | } \ | |
366 | }; \ | |
367 | \ | |
368 | extern "C" Expression* \ | |
369 | script_exp_unary_ ## NAME(Expression* arg) \ | |
370 | { \ | |
371 | return new Unary_ ## NAME(arg); \ | |
e5756efb ILT |
372 | } |
373 | ||
374 | UNARY_EXPRESSION(minus, -) | |
375 | UNARY_EXPRESSION(logical_not, !) | |
376 | UNARY_EXPRESSION(bitwise_not, ~) | |
377 | ||
378 | // A binary expression. | |
379 | ||
380 | class Binary_expression : public Expression | |
381 | { | |
382 | public: | |
383 | Binary_expression(Expression* left, Expression* right) | |
384 | : left_(left), right_(right) | |
385 | { } | |
386 | ||
387 | ~Binary_expression() | |
388 | { | |
389 | delete this->left_; | |
390 | delete this->right_; | |
391 | } | |
392 | ||
393 | protected: | |
394 | uint64_t | |
77e65537 | 395 | left_value(const Expression_eval_info* eei, |
f6973bdc ILT |
396 | Output_section** section_pointer, |
397 | uint64_t* alignment_pointer) const | |
77e65537 ILT |
398 | { |
399 | return this->left_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 400 | eei->check_assertions, |
77e65537 ILT |
401 | eei->is_dot_available, |
402 | eei->dot_value, | |
403 | eei->dot_section, | |
f6973bdc | 404 | section_pointer, |
286adcf4 | 405 | alignment_pointer, |
e051745c CC |
406 | NULL, |
407 | NULL, | |
408 | NULL, | |
1757d35c CC |
409 | false, |
410 | eei->is_valid_pointer); | |
77e65537 | 411 | } |
e5756efb ILT |
412 | |
413 | uint64_t | |
77e65537 | 414 | right_value(const Expression_eval_info* eei, |
f6973bdc ILT |
415 | Output_section** section_pointer, |
416 | uint64_t* alignment_pointer) const | |
77e65537 ILT |
417 | { |
418 | return this->right_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 419 | eei->check_assertions, |
77e65537 ILT |
420 | eei->is_dot_available, |
421 | eei->dot_value, | |
422 | eei->dot_section, | |
f6973bdc | 423 | section_pointer, |
286adcf4 | 424 | alignment_pointer, |
e051745c CC |
425 | NULL, |
426 | NULL, | |
427 | NULL, | |
1757d35c CC |
428 | false, |
429 | eei->is_valid_pointer); | |
77e65537 | 430 | } |
e5756efb | 431 | |
494e05f4 ILT |
432 | void |
433 | left_print(FILE* f) const | |
434 | { this->left_->print(f); } | |
435 | ||
436 | void | |
437 | right_print(FILE* f) const | |
438 | { this->right_->print(f); } | |
439 | ||
440 | // This is a call to function FUNCTION_NAME. Print it. This is for | |
441 | // debugging. | |
442 | void | |
ca09d69a | 443 | print_function(FILE* f, const char* function_name) const |
494e05f4 ILT |
444 | { |
445 | fprintf(f, "%s(", function_name); | |
446 | this->left_print(f); | |
447 | fprintf(f, ", "); | |
448 | this->right_print(f); | |
449 | fprintf(f, ")"); | |
450 | } | |
451 | ||
3281b315 ST |
452 | void |
453 | set_expr_sym_in_real_elf(Symbol_table* symtab) const | |
454 | { | |
455 | this->left_->set_expr_sym_in_real_elf(symtab); | |
456 | this->right_->set_expr_sym_in_real_elf(symtab); | |
457 | } | |
458 | ||
e5756efb ILT |
459 | private: |
460 | Expression* left_; | |
461 | Expression* right_; | |
462 | }; | |
463 | ||
464 | // Handle binary operators. We use a preprocessor macro as a hack to | |
77e65537 ILT |
465 | // capture the C operator. KEEP_LEFT means that if the left operand |
466 | // is section relative and the right operand is not, the result uses | |
467 | // the same section as the left operand. KEEP_RIGHT is the same with | |
468 | // left and right swapped. IS_DIV means that we need to give an error | |
469 | // if the right operand is zero. WARN means that we should warn if | |
470 | // used on section relative values in a relocatable link. We always | |
471 | // warn if used on values in different sections in a relocatable link. | |
472 | ||
473 | #define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ | |
e5756efb ILT |
474 | class Binary_ ## NAME : public Binary_expression \ |
475 | { \ | |
476 | public: \ | |
477 | Binary_ ## NAME(Expression* left, Expression* right) \ | |
478 | : Binary_expression(left, right) \ | |
479 | { } \ | |
480 | \ | |
481 | uint64_t \ | |
482 | value(const Expression_eval_info* eei) \ | |
483 | { \ | |
77e65537 | 484 | Output_section* left_section; \ |
0ad220c9 | 485 | uint64_t left_alignment = 0; \ |
f6973bdc ILT |
486 | uint64_t left = this->left_value(eei, &left_section, \ |
487 | &left_alignment); \ | |
77e65537 | 488 | Output_section* right_section; \ |
0ad220c9 | 489 | uint64_t right_alignment = 0; \ |
f6973bdc ILT |
490 | uint64_t right = this->right_value(eei, &right_section, \ |
491 | &right_alignment); \ | |
77e65537 | 492 | if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ |
f6973bdc | 493 | { \ |
bacff3ab NC |
494 | if (eei->result_section_pointer != NULL) \ |
495 | *eei->result_section_pointer = right_section; \ | |
0ad220c9 DK |
496 | if (eei->result_alignment_pointer != NULL \ |
497 | && right_alignment > *eei->result_alignment_pointer) \ | |
f6973bdc ILT |
498 | *eei->result_alignment_pointer = right_alignment; \ |
499 | } \ | |
77e65537 ILT |
500 | else if (KEEP_LEFT \ |
501 | && left_section != NULL \ | |
502 | && right_section == NULL) \ | |
f6973bdc | 503 | { \ |
bacff3ab NC |
504 | if (eei->result_section_pointer != NULL) \ |
505 | *eei->result_section_pointer = left_section; \ | |
0ad220c9 DK |
506 | if (eei->result_alignment_pointer != NULL \ |
507 | && left_alignment > *eei->result_alignment_pointer) \ | |
508 | *eei->result_alignment_pointer = left_alignment; \ | |
f6973bdc | 509 | } \ |
77e65537 ILT |
510 | else if ((WARN || left_section != right_section) \ |
511 | && (left_section != NULL || right_section != NULL) \ | |
8851ecca | 512 | && parameters->options().relocatable()) \ |
77e65537 ILT |
513 | gold_warning(_("binary " #NAME " applied to section " \ |
514 | "relative value")); \ | |
515 | if (IS_DIV && right == 0) \ | |
516 | { \ | |
517 | gold_error(_(#NAME " by zero")); \ | |
518 | return 0; \ | |
519 | } \ | |
520 | return left OPERATOR right; \ | |
494e05f4 ILT |
521 | } \ |
522 | \ | |
523 | void \ | |
524 | print(FILE* f) const \ | |
525 | { \ | |
526 | fprintf(f, "("); \ | |
527 | this->left_print(f); \ | |
528 | fprintf(f, " %s ", #OPERATOR); \ | |
529 | this->right_print(f); \ | |
530 | fprintf(f, ")"); \ | |
e5756efb ILT |
531 | } \ |
532 | }; \ | |
533 | \ | |
534 | extern "C" Expression* \ | |
535 | script_exp_binary_ ## NAME(Expression* left, Expression* right) \ | |
536 | { \ | |
537 | return new Binary_ ## NAME(left, right); \ | |
538 | } | |
539 | ||
77e65537 ILT |
540 | BINARY_EXPRESSION(mult, *, false, false, false, true) |
541 | BINARY_EXPRESSION(div, /, false, false, true, true) | |
542 | BINARY_EXPRESSION(mod, %, false, false, true, true) | |
543 | BINARY_EXPRESSION(add, +, true, true, false, true) | |
544 | BINARY_EXPRESSION(sub, -, true, false, false, false) | |
545 | BINARY_EXPRESSION(lshift, <<, false, false, false, true) | |
546 | BINARY_EXPRESSION(rshift, >>, false, false, false, true) | |
547 | BINARY_EXPRESSION(eq, ==, false, false, false, false) | |
548 | BINARY_EXPRESSION(ne, !=, false, false, false, false) | |
549 | BINARY_EXPRESSION(le, <=, false, false, false, false) | |
550 | BINARY_EXPRESSION(ge, >=, false, false, false, false) | |
551 | BINARY_EXPRESSION(lt, <, false, false, false, false) | |
552 | BINARY_EXPRESSION(gt, >, false, false, false, false) | |
553 | BINARY_EXPRESSION(bitwise_and, &, true, true, false, true) | |
554 | BINARY_EXPRESSION(bitwise_xor, ^, true, true, false, true) | |
555 | BINARY_EXPRESSION(bitwise_or, |, true, true, false, true) | |
556 | BINARY_EXPRESSION(logical_and, &&, false, false, false, true) | |
557 | BINARY_EXPRESSION(logical_or, ||, false, false, false, true) | |
e5756efb ILT |
558 | |
559 | // A trinary expression. | |
560 | ||
561 | class Trinary_expression : public Expression | |
562 | { | |
563 | public: | |
564 | Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3) | |
565 | : arg1_(arg1), arg2_(arg2), arg3_(arg3) | |
566 | { } | |
567 | ||
568 | ~Trinary_expression() | |
569 | { | |
570 | delete this->arg1_; | |
571 | delete this->arg2_; | |
572 | delete this->arg3_; | |
573 | } | |
574 | ||
575 | protected: | |
576 | uint64_t | |
77e65537 ILT |
577 | arg1_value(const Expression_eval_info* eei, |
578 | Output_section** section_pointer) const | |
579 | { | |
580 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 581 | eei->check_assertions, |
77e65537 ILT |
582 | eei->is_dot_available, |
583 | eei->dot_value, | |
584 | eei->dot_section, | |
f6973bdc | 585 | section_pointer, |
286adcf4 | 586 | NULL, |
e051745c CC |
587 | NULL, |
588 | NULL, | |
589 | NULL, | |
1757d35c CC |
590 | false, |
591 | eei->is_valid_pointer); | |
77e65537 | 592 | } |
e5756efb ILT |
593 | |
594 | uint64_t | |
77e65537 | 595 | arg2_value(const Expression_eval_info* eei, |
f6973bdc ILT |
596 | Output_section** section_pointer, |
597 | uint64_t* alignment_pointer) const | |
77e65537 ILT |
598 | { |
599 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 600 | eei->check_assertions, |
77e65537 ILT |
601 | eei->is_dot_available, |
602 | eei->dot_value, | |
603 | eei->dot_section, | |
f6973bdc | 604 | section_pointer, |
286adcf4 | 605 | alignment_pointer, |
e051745c CC |
606 | NULL, |
607 | NULL, | |
608 | NULL, | |
1757d35c CC |
609 | false, |
610 | eei->is_valid_pointer); | |
77e65537 | 611 | } |
e5756efb ILT |
612 | |
613 | uint64_t | |
77e65537 | 614 | arg3_value(const Expression_eval_info* eei, |
f6973bdc ILT |
615 | Output_section** section_pointer, |
616 | uint64_t* alignment_pointer) const | |
77e65537 ILT |
617 | { |
618 | return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, | |
919ed24c | 619 | eei->check_assertions, |
77e65537 ILT |
620 | eei->is_dot_available, |
621 | eei->dot_value, | |
622 | eei->dot_section, | |
f6973bdc | 623 | section_pointer, |
286adcf4 | 624 | alignment_pointer, |
e051745c CC |
625 | NULL, |
626 | NULL, | |
627 | NULL, | |
1757d35c CC |
628 | false, |
629 | eei->is_valid_pointer); | |
77e65537 | 630 | } |
e5756efb | 631 | |
494e05f4 ILT |
632 | void |
633 | arg1_print(FILE* f) const | |
634 | { this->arg1_->print(f); } | |
635 | ||
636 | void | |
637 | arg2_print(FILE* f) const | |
638 | { this->arg2_->print(f); } | |
639 | ||
640 | void | |
641 | arg3_print(FILE* f) const | |
642 | { this->arg3_->print(f); } | |
643 | ||
3281b315 ST |
644 | void |
645 | set_expr_sym_in_real_elf(Symbol_table* symtab) const | |
646 | { | |
647 | this->arg1_->set_expr_sym_in_real_elf(symtab); | |
648 | this->arg2_->set_expr_sym_in_real_elf(symtab); | |
649 | this->arg3_->set_expr_sym_in_real_elf(symtab); | |
650 | } | |
651 | ||
e5756efb ILT |
652 | private: |
653 | Expression* arg1_; | |
654 | Expression* arg2_; | |
655 | Expression* arg3_; | |
656 | }; | |
657 | ||
658 | // The conditional operator. | |
659 | ||
660 | class Trinary_cond : public Trinary_expression | |
661 | { | |
662 | public: | |
663 | Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
664 | : Trinary_expression(arg1, arg2, arg3) | |
665 | { } | |
666 | ||
667 | uint64_t | |
668 | value(const Expression_eval_info* eei) | |
669 | { | |
77e65537 ILT |
670 | Output_section* arg1_section; |
671 | uint64_t arg1 = this->arg1_value(eei, &arg1_section); | |
672 | return (arg1 | |
f6973bdc ILT |
673 | ? this->arg2_value(eei, eei->result_section_pointer, |
674 | eei->result_alignment_pointer) | |
675 | : this->arg3_value(eei, eei->result_section_pointer, | |
676 | eei->result_alignment_pointer)); | |
e5756efb | 677 | } |
494e05f4 ILT |
678 | |
679 | void | |
680 | print(FILE* f) const | |
681 | { | |
682 | fprintf(f, "("); | |
683 | this->arg1_print(f); | |
684 | fprintf(f, " ? "); | |
685 | this->arg2_print(f); | |
686 | fprintf(f, " : "); | |
687 | this->arg3_print(f); | |
688 | fprintf(f, ")"); | |
689 | } | |
e5756efb ILT |
690 | }; |
691 | ||
692 | extern "C" Expression* | |
693 | script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
694 | { | |
695 | return new Trinary_cond(arg1, arg2, arg3); | |
696 | } | |
697 | ||
698 | // Max function. | |
699 | ||
700 | class Max_expression : public Binary_expression | |
701 | { | |
702 | public: | |
703 | Max_expression(Expression* left, Expression* right) | |
704 | : Binary_expression(left, right) | |
705 | { } | |
706 | ||
707 | uint64_t | |
708 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
709 | { |
710 | Output_section* left_section; | |
f6973bdc ILT |
711 | uint64_t left_alignment; |
712 | uint64_t left = this->left_value(eei, &left_section, &left_alignment); | |
77e65537 | 713 | Output_section* right_section; |
f6973bdc ILT |
714 | uint64_t right_alignment; |
715 | uint64_t right = this->right_value(eei, &right_section, &right_alignment); | |
77e65537 | 716 | if (left_section == right_section) |
bacff3ab NC |
717 | { |
718 | if (eei->result_section_pointer != NULL) | |
719 | *eei->result_section_pointer = left_section; | |
720 | } | |
77e65537 | 721 | else if ((left_section != NULL || right_section != NULL) |
8851ecca | 722 | && parameters->options().relocatable()) |
77e65537 | 723 | gold_warning(_("max applied to section relative value")); |
f6973bdc ILT |
724 | if (eei->result_alignment_pointer != NULL) |
725 | { | |
726 | uint64_t ra = *eei->result_alignment_pointer; | |
727 | if (left > right) | |
728 | ra = std::max(ra, left_alignment); | |
729 | else if (right > left) | |
730 | ra = std::max(ra, right_alignment); | |
731 | else | |
732 | ra = std::max(ra, std::max(left_alignment, right_alignment)); | |
733 | *eei->result_alignment_pointer = ra; | |
734 | } | |
77e65537 ILT |
735 | return std::max(left, right); |
736 | } | |
494e05f4 ILT |
737 | |
738 | void | |
739 | print(FILE* f) const | |
740 | { this->print_function(f, "MAX"); } | |
e5756efb ILT |
741 | }; |
742 | ||
743 | extern "C" Expression* | |
744 | script_exp_function_max(Expression* left, Expression* right) | |
745 | { | |
746 | return new Max_expression(left, right); | |
747 | } | |
748 | ||
749 | // Min function. | |
750 | ||
751 | class Min_expression : public Binary_expression | |
752 | { | |
753 | public: | |
754 | Min_expression(Expression* left, Expression* right) | |
755 | : Binary_expression(left, right) | |
756 | { } | |
757 | ||
758 | uint64_t | |
759 | value(const Expression_eval_info* eei) | |
77e65537 ILT |
760 | { |
761 | Output_section* left_section; | |
f6973bdc ILT |
762 | uint64_t left_alignment; |
763 | uint64_t left = this->left_value(eei, &left_section, &left_alignment); | |
77e65537 | 764 | Output_section* right_section; |
f6973bdc ILT |
765 | uint64_t right_alignment; |
766 | uint64_t right = this->right_value(eei, &right_section, &right_alignment); | |
77e65537 | 767 | if (left_section == right_section) |
bacff3ab NC |
768 | { |
769 | if (eei->result_section_pointer != NULL) | |
770 | *eei->result_section_pointer = left_section; | |
771 | } | |
77e65537 | 772 | else if ((left_section != NULL || right_section != NULL) |
8851ecca | 773 | && parameters->options().relocatable()) |
77e65537 | 774 | gold_warning(_("min applied to section relative value")); |
f6973bdc ILT |
775 | if (eei->result_alignment_pointer != NULL) |
776 | { | |
777 | uint64_t ra = *eei->result_alignment_pointer; | |
778 | if (left < right) | |
779 | ra = std::max(ra, left_alignment); | |
780 | else if (right < left) | |
781 | ra = std::max(ra, right_alignment); | |
782 | else | |
783 | ra = std::max(ra, std::max(left_alignment, right_alignment)); | |
784 | *eei->result_alignment_pointer = ra; | |
785 | } | |
77e65537 ILT |
786 | return std::min(left, right); |
787 | } | |
494e05f4 ILT |
788 | |
789 | void | |
790 | print(FILE* f) const | |
791 | { this->print_function(f, "MIN"); } | |
e5756efb ILT |
792 | }; |
793 | ||
794 | extern "C" Expression* | |
795 | script_exp_function_min(Expression* left, Expression* right) | |
796 | { | |
797 | return new Min_expression(left, right); | |
798 | } | |
799 | ||
7508a093 ILT |
800 | // Class Section_expression. This is a parent class used for |
801 | // functions which take the name of an output section. | |
802 | ||
803 | class Section_expression : public Expression | |
804 | { | |
805 | public: | |
806 | Section_expression(const char* section_name, size_t section_name_len) | |
807 | : section_name_(section_name, section_name_len) | |
808 | { } | |
809 | ||
810 | uint64_t | |
811 | value(const Expression_eval_info*); | |
812 | ||
813 | void | |
814 | print(FILE* f) const | |
815 | { fprintf(f, "%s(%s)", this->function_name(), this->section_name_.c_str()); } | |
816 | ||
817 | protected: | |
818 | // The child class must implement this. | |
819 | virtual uint64_t | |
820 | value_from_output_section(const Expression_eval_info*, | |
821 | Output_section*) = 0; | |
822 | ||
8f2eb564 ILT |
823 | // The child class must implement this. |
824 | virtual uint64_t | |
825 | value_from_script_output_section(uint64_t address, uint64_t load_address, | |
826 | uint64_t addralign, uint64_t size) = 0; | |
827 | ||
7508a093 ILT |
828 | // The child class must implement this. |
829 | virtual const char* | |
830 | function_name() const = 0; | |
831 | ||
832 | private: | |
833 | std::string section_name_; | |
834 | }; | |
835 | ||
836 | uint64_t | |
837 | Section_expression::value(const Expression_eval_info* eei) | |
838 | { | |
839 | const char* section_name = this->section_name_.c_str(); | |
840 | Output_section* os = eei->layout->find_output_section(section_name); | |
8f2eb564 ILT |
841 | if (os != NULL) |
842 | return this->value_from_output_section(eei, os); | |
843 | ||
844 | uint64_t address; | |
845 | uint64_t load_address; | |
846 | uint64_t addralign; | |
847 | uint64_t size; | |
848 | const Script_options* ss = eei->layout->script_options(); | |
849 | if (ss->saw_sections_clause()) | |
7508a093 | 850 | { |
8f2eb564 ILT |
851 | if (ss->script_sections()->get_output_section_info(section_name, |
852 | &address, | |
853 | &load_address, | |
854 | &addralign, | |
855 | &size)) | |
856 | return this->value_from_script_output_section(address, load_address, | |
857 | addralign, size); | |
7508a093 ILT |
858 | } |
859 | ||
8f2eb564 ILT |
860 | gold_error("%s called on nonexistent output section '%s'", |
861 | this->function_name(), section_name); | |
862 | return 0; | |
7508a093 ILT |
863 | } |
864 | ||
3edc73f2 ILT |
865 | // ABSOLUTE function. |
866 | ||
867 | class Absolute_expression : public Unary_expression | |
868 | { | |
869 | public: | |
870 | Absolute_expression(Expression* arg) | |
871 | : Unary_expression(arg) | |
872 | { } | |
873 | ||
874 | uint64_t | |
875 | value(const Expression_eval_info* eei) | |
876 | { | |
bacff3ab | 877 | uint64_t ret = this->arg_value(eei, NULL); |
3edc73f2 | 878 | // Force the value to be absolute. |
bacff3ab NC |
879 | if (eei->result_section_pointer != NULL) |
880 | *eei->result_section_pointer = NULL; | |
3edc73f2 ILT |
881 | return ret; |
882 | } | |
883 | ||
884 | void | |
885 | print(FILE* f) const | |
886 | { | |
887 | fprintf(f, "ABSOLUTE("); | |
888 | this->arg_print(f); | |
889 | fprintf(f, ")"); | |
890 | } | |
891 | }; | |
892 | ||
893 | extern "C" Expression* | |
894 | script_exp_function_absolute(Expression* arg) | |
895 | { | |
896 | return new Absolute_expression(arg); | |
897 | } | |
898 | ||
899 | // ALIGN function. | |
e5756efb ILT |
900 | |
901 | class Align_expression : public Binary_expression | |
902 | { | |
903 | public: | |
904 | Align_expression(Expression* left, Expression* right) | |
905 | : Binary_expression(left, right) | |
906 | { } | |
907 | ||
908 | uint64_t | |
909 | value(const Expression_eval_info* eei) | |
910 | { | |
77e65537 | 911 | Output_section* align_section; |
f6973bdc | 912 | uint64_t align = this->right_value(eei, &align_section, NULL); |
77e65537 | 913 | if (align_section != NULL |
8851ecca | 914 | && parameters->options().relocatable()) |
77e65537 ILT |
915 | gold_warning(_("aligning to section relative value")); |
916 | ||
f6973bdc ILT |
917 | if (eei->result_alignment_pointer != NULL |
918 | && align > *eei->result_alignment_pointer) | |
919 | { | |
920 | uint64_t a = align; | |
921 | while ((a & (a - 1)) != 0) | |
922 | a &= a - 1; | |
923 | *eei->result_alignment_pointer = a; | |
924 | } | |
925 | ||
926 | uint64_t value = this->left_value(eei, eei->result_section_pointer, NULL); | |
e5756efb | 927 | if (align <= 1) |
2ea97941 ILT |
928 | return value; |
929 | return ((value + align - 1) / align) * align; | |
e5756efb | 930 | } |
494e05f4 ILT |
931 | |
932 | void | |
933 | print(FILE* f) const | |
934 | { this->print_function(f, "ALIGN"); } | |
e5756efb ILT |
935 | }; |
936 | ||
937 | extern "C" Expression* | |
938 | script_exp_function_align(Expression* left, Expression* right) | |
939 | { | |
940 | return new Align_expression(left, right); | |
941 | } | |
942 | ||
3edc73f2 | 943 | // ASSERT function. |
e5756efb ILT |
944 | |
945 | class Assert_expression : public Unary_expression | |
946 | { | |
947 | public: | |
948 | Assert_expression(Expression* arg, const char* message, size_t length) | |
949 | : Unary_expression(arg), message_(message, length) | |
950 | { } | |
951 | ||
952 | uint64_t | |
953 | value(const Expression_eval_info* eei) | |
954 | { | |
2ea97941 ILT |
955 | uint64_t value = this->arg_value(eei, eei->result_section_pointer); |
956 | if (!value && eei->check_assertions) | |
e5756efb | 957 | gold_error("%s", this->message_.c_str()); |
2ea97941 | 958 | return value; |
e5756efb ILT |
959 | } |
960 | ||
494e05f4 ILT |
961 | void |
962 | print(FILE* f) const | |
963 | { | |
964 | fprintf(f, "ASSERT("); | |
965 | this->arg_print(f); | |
966 | fprintf(f, ", %s)", this->message_.c_str()); | |
967 | } | |
968 | ||
e5756efb ILT |
969 | private: |
970 | std::string message_; | |
971 | }; | |
972 | ||
973 | extern "C" Expression* | |
974 | script_exp_function_assert(Expression* expr, const char* message, | |
975 | size_t length) | |
976 | { | |
977 | return new Assert_expression(expr, message, length); | |
978 | } | |
979 | ||
7508a093 | 980 | // ADDR function. |
494e05f4 | 981 | |
7508a093 | 982 | class Addr_expression : public Section_expression |
494e05f4 ILT |
983 | { |
984 | public: | |
985 | Addr_expression(const char* section_name, size_t section_name_len) | |
7508a093 | 986 | : Section_expression(section_name, section_name_len) |
494e05f4 ILT |
987 | { } |
988 | ||
7508a093 | 989 | protected: |
494e05f4 | 990 | uint64_t |
3edc73f2 | 991 | value_from_output_section(const Expression_eval_info* eei, |
7508a093 ILT |
992 | Output_section* os) |
993 | { | |
bacff3ab NC |
994 | if (eei->result_section_pointer != NULL) |
995 | *eei->result_section_pointer = os; | |
1757d35c CC |
996 | if (os->is_address_valid()) |
997 | return os->address(); | |
998 | *eei->is_valid_pointer = false; | |
999 | return 0; | |
7508a093 | 1000 | } |
494e05f4 | 1001 | |
8f2eb564 ILT |
1002 | uint64_t |
1003 | value_from_script_output_section(uint64_t address, uint64_t, uint64_t, | |
1004 | uint64_t) | |
1005 | { return address; } | |
1006 | ||
7508a093 ILT |
1007 | const char* |
1008 | function_name() const | |
1009 | { return "ADDR"; } | |
494e05f4 ILT |
1010 | }; |
1011 | ||
494e05f4 ILT |
1012 | extern "C" Expression* |
1013 | script_exp_function_addr(const char* section_name, size_t section_name_len) | |
1014 | { | |
1015 | return new Addr_expression(section_name, section_name_len); | |
1016 | } | |
1017 | ||
3edc73f2 ILT |
1018 | // ALIGNOF. |
1019 | ||
1020 | class Alignof_expression : public Section_expression | |
1021 | { | |
1022 | public: | |
1023 | Alignof_expression(const char* section_name, size_t section_name_len) | |
1024 | : Section_expression(section_name, section_name_len) | |
1025 | { } | |
1026 | ||
1027 | protected: | |
1028 | uint64_t | |
1029 | value_from_output_section(const Expression_eval_info*, | |
1030 | Output_section* os) | |
1031 | { return os->addralign(); } | |
1032 | ||
8f2eb564 ILT |
1033 | uint64_t |
1034 | value_from_script_output_section(uint64_t, uint64_t, uint64_t addralign, | |
1035 | uint64_t) | |
1036 | { return addralign; } | |
1037 | ||
3edc73f2 ILT |
1038 | const char* |
1039 | function_name() const | |
1040 | { return "ALIGNOF"; } | |
1041 | }; | |
1042 | ||
1043 | extern "C" Expression* | |
1044 | script_exp_function_alignof(const char* section_name, size_t section_name_len) | |
1045 | { | |
1046 | return new Alignof_expression(section_name, section_name_len); | |
1047 | } | |
1048 | ||
3802b2dd ILT |
1049 | // CONSTANT. It would be nice if we could simply evaluate this |
1050 | // immediately and return an Integer_expression, but unfortunately we | |
1051 | // don't know the target. | |
1052 | ||
1053 | class Constant_expression : public Expression | |
1054 | { | |
1055 | public: | |
1056 | Constant_expression(const char* name, size_t length); | |
1057 | ||
1058 | uint64_t | |
1059 | value(const Expression_eval_info*); | |
1060 | ||
1061 | void | |
1062 | print(FILE* f) const; | |
1063 | ||
1064 | private: | |
1065 | enum Constant_function | |
1066 | { | |
1067 | CONSTANT_MAXPAGESIZE, | |
1068 | CONSTANT_COMMONPAGESIZE | |
1069 | }; | |
e5756efb | 1070 | |
3802b2dd ILT |
1071 | Constant_function function_; |
1072 | }; | |
1073 | ||
1074 | Constant_expression::Constant_expression(const char* name, size_t length) | |
1075 | { | |
1076 | if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) | |
1077 | this->function_ = CONSTANT_MAXPAGESIZE; | |
1078 | else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) | |
1079 | this->function_ = CONSTANT_COMMONPAGESIZE; | |
1080 | else | |
1081 | { | |
1082 | std::string s(name, length); | |
1083 | gold_error(_("unknown constant %s"), s.c_str()); | |
1084 | this->function_ = CONSTANT_MAXPAGESIZE; | |
1085 | } | |
1086 | } | |
1087 | ||
1088 | uint64_t | |
1089 | Constant_expression::value(const Expression_eval_info*) | |
1090 | { | |
1091 | switch (this->function_) | |
1092 | { | |
1093 | case CONSTANT_MAXPAGESIZE: | |
8851ecca | 1094 | return parameters->target().abi_pagesize(); |
3802b2dd | 1095 | case CONSTANT_COMMONPAGESIZE: |
8851ecca | 1096 | return parameters->target().common_pagesize(); |
3802b2dd ILT |
1097 | default: |
1098 | gold_unreachable(); | |
1099 | } | |
1100 | } | |
1101 | ||
1102 | void | |
1103 | Constant_expression::print(FILE* f) const | |
1104 | { | |
1105 | const char* name; | |
1106 | switch (this->function_) | |
1107 | { | |
1108 | case CONSTANT_MAXPAGESIZE: | |
1109 | name = "MAXPAGESIZE"; | |
1110 | break; | |
1111 | case CONSTANT_COMMONPAGESIZE: | |
1112 | name = "COMMONPAGESIZE"; | |
1113 | break; | |
1114 | default: | |
1115 | gold_unreachable(); | |
1116 | } | |
1117 | fprintf(f, "CONSTANT(%s)", name); | |
1118 | } | |
1119 | ||
e5756efb | 1120 | extern "C" Expression* |
3802b2dd | 1121 | script_exp_function_constant(const char* name, size_t length) |
e5756efb | 1122 | { |
3802b2dd | 1123 | return new Constant_expression(name, length); |
e5756efb ILT |
1124 | } |
1125 | ||
3802b2dd ILT |
1126 | // DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall |
1127 | // back to the general case. | |
1128 | ||
e5756efb | 1129 | extern "C" Expression* |
3802b2dd | 1130 | script_exp_function_data_segment_align(Expression* left, Expression*) |
e5756efb | 1131 | { |
3802b2dd ILT |
1132 | Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); |
1133 | Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); | |
1134 | Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), | |
1135 | e2); | |
1136 | return script_exp_binary_add(e1, e3); | |
e5756efb ILT |
1137 | } |
1138 | ||
3802b2dd ILT |
1139 | // DATA_SEGMENT_RELRO. FIXME: This is not implemented. |
1140 | ||
e5756efb | 1141 | extern "C" Expression* |
3802b2dd | 1142 | script_exp_function_data_segment_relro_end(Expression*, Expression* right) |
e5756efb | 1143 | { |
3802b2dd | 1144 | return right; |
e5756efb ILT |
1145 | } |
1146 | ||
3802b2dd ILT |
1147 | // DATA_SEGMENT_END. FIXME: This is not implemented. |
1148 | ||
e5756efb | 1149 | extern "C" Expression* |
3802b2dd | 1150 | script_exp_function_data_segment_end(Expression* val) |
e5756efb | 1151 | { |
3802b2dd ILT |
1152 | return val; |
1153 | } | |
1154 | ||
3edc73f2 ILT |
1155 | // DEFINED function. |
1156 | ||
1157 | class Defined_expression : public Expression | |
1158 | { | |
1159 | public: | |
1160 | Defined_expression(const char* symbol_name, size_t symbol_name_len) | |
1161 | : symbol_name_(symbol_name, symbol_name_len) | |
1162 | { } | |
1163 | ||
1164 | uint64_t | |
1165 | value(const Expression_eval_info* eei) | |
1166 | { | |
1167 | Symbol* sym = eei->symtab->lookup(this->symbol_name_.c_str()); | |
1168 | return sym != NULL && sym->is_defined(); | |
1169 | } | |
1170 | ||
1171 | void | |
1172 | print(FILE* f) const | |
1173 | { fprintf(f, "DEFINED(%s)", this->symbol_name_.c_str()); } | |
1174 | ||
1175 | private: | |
1176 | std::string symbol_name_; | |
1177 | }; | |
1178 | ||
1179 | extern "C" Expression* | |
1180 | script_exp_function_defined(const char* symbol_name, size_t symbol_name_len) | |
1181 | { | |
1182 | return new Defined_expression(symbol_name, symbol_name_len); | |
1183 | } | |
1184 | ||
7508a093 ILT |
1185 | // LOADADDR function |
1186 | ||
1187 | class Loadaddr_expression : public Section_expression | |
1188 | { | |
1189 | public: | |
1190 | Loadaddr_expression(const char* section_name, size_t section_name_len) | |
1191 | : Section_expression(section_name, section_name_len) | |
1192 | { } | |
1193 | ||
1194 | protected: | |
1195 | uint64_t | |
3edc73f2 | 1196 | value_from_output_section(const Expression_eval_info* eei, |
7508a093 ILT |
1197 | Output_section* os) |
1198 | { | |
1199 | if (os->has_load_address()) | |
1200 | return os->load_address(); | |
1201 | else | |
1202 | { | |
bacff3ab NC |
1203 | if (eei->result_section_pointer != NULL) |
1204 | *eei->result_section_pointer = os; | |
7508a093 ILT |
1205 | return os->address(); |
1206 | } | |
1207 | } | |
1208 | ||
8f2eb564 ILT |
1209 | uint64_t |
1210 | value_from_script_output_section(uint64_t, uint64_t load_address, uint64_t, | |
1211 | uint64_t) | |
1212 | { return load_address; } | |
1213 | ||
7508a093 ILT |
1214 | const char* |
1215 | function_name() const | |
1216 | { return "LOADADDR"; } | |
1217 | }; | |
1218 | ||
1219 | extern "C" Expression* | |
1220 | script_exp_function_loadaddr(const char* section_name, size_t section_name_len) | |
1221 | { | |
1222 | return new Loadaddr_expression(section_name, section_name_len); | |
1223 | } | |
1224 | ||
1225 | // SIZEOF function | |
1226 | ||
1227 | class Sizeof_expression : public Section_expression | |
1228 | { | |
1229 | public: | |
1230 | Sizeof_expression(const char* section_name, size_t section_name_len) | |
1231 | : Section_expression(section_name, section_name_len) | |
1232 | { } | |
1233 | ||
1234 | protected: | |
1235 | uint64_t | |
3edc73f2 | 1236 | value_from_output_section(const Expression_eval_info*, |
7508a093 ILT |
1237 | Output_section* os) |
1238 | { | |
1239 | // We can not use data_size here, as the size of the section may | |
1240 | // not have been finalized. Instead we get whatever the current | |
1241 | // size is. This will work correctly for backward references in | |
1242 | // linker scripts. | |
1243 | return os->current_data_size(); | |
1244 | } | |
1245 | ||
8f2eb564 ILT |
1246 | uint64_t |
1247 | value_from_script_output_section(uint64_t, uint64_t, uint64_t, | |
1248 | uint64_t size) | |
1249 | { return size; } | |
1250 | ||
7508a093 ILT |
1251 | const char* |
1252 | function_name() const | |
1253 | { return "SIZEOF"; } | |
1254 | }; | |
1255 | ||
1256 | extern "C" Expression* | |
1257 | script_exp_function_sizeof(const char* section_name, size_t section_name_len) | |
1258 | { | |
1259 | return new Sizeof_expression(section_name, section_name_len); | |
1260 | } | |
1261 | ||
3802b2dd ILT |
1262 | // SIZEOF_HEADERS. |
1263 | ||
1264 | class Sizeof_headers_expression : public Expression | |
1265 | { | |
1266 | public: | |
1267 | Sizeof_headers_expression() | |
1268 | { } | |
1269 | ||
1270 | uint64_t | |
1271 | value(const Expression_eval_info*); | |
1272 | ||
1273 | void | |
1274 | print(FILE* f) const | |
1275 | { fprintf(f, "SIZEOF_HEADERS"); } | |
1276 | }; | |
1277 | ||
1278 | uint64_t | |
1279 | Sizeof_headers_expression::value(const Expression_eval_info* eei) | |
1280 | { | |
1281 | unsigned int ehdr_size; | |
1282 | unsigned int phdr_size; | |
8851ecca | 1283 | if (parameters->target().get_size() == 32) |
3802b2dd ILT |
1284 | { |
1285 | ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; | |
1286 | phdr_size = elfcpp::Elf_sizes<32>::phdr_size; | |
1287 | } | |
8851ecca | 1288 | else if (parameters->target().get_size() == 64) |
3802b2dd ILT |
1289 | { |
1290 | ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; | |
1291 | phdr_size = elfcpp::Elf_sizes<64>::phdr_size; | |
1292 | } | |
1293 | else | |
1294 | gold_unreachable(); | |
1295 | ||
1296 | return ehdr_size + phdr_size * eei->layout->expected_segment_count(); | |
e5756efb ILT |
1297 | } |
1298 | ||
e5756efb | 1299 | extern "C" Expression* |
3802b2dd | 1300 | script_exp_function_sizeof_headers() |
e5756efb | 1301 | { |
3802b2dd | 1302 | return new Sizeof_headers_expression(); |
e5756efb ILT |
1303 | } |
1304 | ||
3c12dcdb DK |
1305 | // SEGMENT_START. |
1306 | ||
1307 | class Segment_start_expression : public Unary_expression | |
1308 | { | |
1309 | public: | |
1310 | Segment_start_expression(const char* segment_name, size_t segment_name_len, | |
1311 | Expression* default_value) | |
1312 | : Unary_expression(default_value), | |
1313 | segment_name_(segment_name, segment_name_len) | |
1314 | { } | |
1315 | ||
1316 | uint64_t | |
1317 | value(const Expression_eval_info*); | |
1318 | ||
1319 | void | |
1320 | print(FILE* f) const | |
1321 | { | |
1322 | fprintf(f, "SEGMENT_START(\"%s\", ", this->segment_name_.c_str()); | |
1323 | this->arg_print(f); | |
1324 | fprintf(f, ")"); | |
1325 | } | |
1326 | ||
1327 | private: | |
1328 | std::string segment_name_; | |
1329 | }; | |
1330 | ||
1331 | uint64_t | |
1332 | Segment_start_expression::value(const Expression_eval_info* eei) | |
1333 | { | |
1334 | // Check for command line overrides. | |
1335 | if (parameters->options().user_set_Ttext() | |
1336 | && this->segment_name_ == ".text") | |
1337 | return parameters->options().Ttext(); | |
1338 | else if (parameters->options().user_set_Tdata() | |
1339 | && this->segment_name_ == ".data") | |
1340 | return parameters->options().Tdata(); | |
1341 | else if (parameters->options().user_set_Tbss() | |
1342 | && this->segment_name_ == ".bss") | |
1343 | return parameters->options().Tbss(); | |
1344 | else | |
1345 | { | |
bacff3ab | 1346 | uint64_t ret = this->arg_value(eei, NULL); |
3c12dcdb | 1347 | // Force the value to be absolute. |
bacff3ab NC |
1348 | if (eei->result_section_pointer != NULL) |
1349 | *eei->result_section_pointer = NULL; | |
3c12dcdb DK |
1350 | return ret; |
1351 | } | |
1352 | } | |
3802b2dd | 1353 | |
e5756efb | 1354 | extern "C" Expression* |
3c12dcdb DK |
1355 | script_exp_function_segment_start(const char* segment_name, |
1356 | size_t segment_name_len, | |
1357 | Expression* default_value) | |
e5756efb | 1358 | { |
3c12dcdb DK |
1359 | return new Segment_start_expression(segment_name, segment_name_len, |
1360 | default_value); | |
e5756efb ILT |
1361 | } |
1362 | ||
e5756efb | 1363 | } // End namespace gold. |