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