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