Commit | Line | Data |
---|---|---|
e5756efb ILT |
1 | // expression.cc -- expressions in linker scripts for gold |
2 | ||
3 | // Copyright 2006, 2007, 2008 Free Software Foundation, Inc. | |
4 | // Written by Ian Lance Taylor <iant@google.com>. | |
5 | ||
6 | // This file is part of gold. | |
7 | ||
8 | // This program is free software; you can redistribute it and/or modify | |
9 | // it under the terms of the GNU General Public License as published by | |
10 | // the Free Software Foundation; either version 3 of the License, or | |
11 | // (at your option) any later version. | |
12 | ||
13 | // This program is distributed in the hope that it will be useful, | |
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | // GNU General Public License for more details. | |
17 | ||
18 | // You should have received a copy of the GNU General Public License | |
19 | // along with this program; if not, write to the Free Software | |
20 | // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | |
21 | // MA 02110-1301, USA. | |
22 | ||
23 | #include "gold.h" | |
24 | ||
25 | #include <string> | |
26 | ||
3802b2dd | 27 | #include "elfcpp.h" |
e5756efb ILT |
28 | #include "parameters.h" |
29 | #include "symtab.h" | |
30 | #include "layout.h" | |
494e05f4 | 31 | #include "output.h" |
e5756efb ILT |
32 | #include "script.h" |
33 | #include "script-c.h" | |
34 | ||
35 | namespace gold | |
36 | { | |
37 | ||
38 | // This file holds the code which handles linker expressions. | |
39 | ||
a445fddf ILT |
40 | // The dot symbol, which linker scripts refer to simply as ".", |
41 | // requires special treatment. The dot symbol is set several times, | |
42 | // section addresses will refer to it, output sections will change it, | |
43 | // and it can be set based on the value of other symbols. We simplify | |
44 | // the handling by prohibiting setting the dot symbol to the value of | |
45 | // a non-absolute symbol. | |
46 | ||
e5756efb ILT |
47 | // When evaluating the value of an expression, we pass in a pointer to |
48 | // this struct, so that the expression evaluation can find the | |
49 | // information it needs. | |
50 | ||
51 | struct Expression::Expression_eval_info | |
52 | { | |
a445fddf | 53 | // The symbol table. |
e5756efb | 54 | const Symbol_table* symtab; |
a445fddf | 55 | // The layout--we use this to get section information. |
e5756efb | 56 | const Layout* layout; |
a445fddf ILT |
57 | // Whether expressions can refer to the dot symbol. The dot symbol |
58 | // is only available within a SECTIONS clause. | |
59 | bool is_dot_available; | |
60 | // Whether the dot symbol currently has a value. | |
61 | bool dot_has_value; | |
62 | // The current value of the dot symbol. | |
63 | uint64_t dot_value; | |
64 | // Points to the IS_ABSOLUTE variable, which is set to false if the | |
65 | // expression uses a value which is not absolute. | |
66 | bool* is_absolute; | |
e5756efb ILT |
67 | }; |
68 | ||
69 | // Evaluate an expression. | |
70 | ||
71 | uint64_t | |
72 | Expression::eval(const Symbol_table* symtab, const Layout* layout) | |
a445fddf ILT |
73 | { |
74 | bool dummy; | |
75 | return this->eval_maybe_dot(symtab, layout, false, false, 0, &dummy); | |
76 | } | |
77 | ||
78 | // Evaluate an expression which may refer to the dot symbol. | |
79 | ||
80 | uint64_t | |
81 | Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, | |
82 | bool dot_has_value, uint64_t dot_value, | |
83 | bool* is_absolute) | |
84 | { | |
85 | return this->eval_maybe_dot(symtab, layout, true, dot_has_value, dot_value, | |
86 | is_absolute); | |
87 | } | |
88 | ||
89 | // Evaluate an expression which may or may not refer to the dot | |
90 | // symbol. | |
91 | ||
92 | uint64_t | |
93 | Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, | |
94 | bool is_dot_available, bool dot_has_value, | |
95 | uint64_t dot_value, bool* is_absolute) | |
e5756efb ILT |
96 | { |
97 | Expression_eval_info eei; | |
98 | eei.symtab = symtab; | |
99 | eei.layout = layout; | |
a445fddf ILT |
100 | eei.is_dot_available = is_dot_available; |
101 | eei.dot_has_value = dot_has_value; | |
102 | eei.dot_value = dot_value; | |
103 | ||
104 | // We assume the value is absolute, and only set this to false if we | |
105 | // find a section relative reference. | |
106 | *is_absolute = true; | |
107 | eei.is_absolute = is_absolute; | |
108 | ||
e5756efb ILT |
109 | return this->value(&eei); |
110 | } | |
111 | ||
112 | // A number. | |
113 | ||
114 | class Integer_expression : public Expression | |
115 | { | |
116 | public: | |
117 | Integer_expression(uint64_t val) | |
118 | : val_(val) | |
119 | { } | |
120 | ||
121 | uint64_t | |
122 | value(const Expression_eval_info*) | |
123 | { return this->val_; } | |
124 | ||
494e05f4 ILT |
125 | void |
126 | print(FILE* f) const | |
127 | { fprintf(f, "0x%llx", static_cast<unsigned long long>(this->val_)); } | |
128 | ||
e5756efb ILT |
129 | private: |
130 | uint64_t val_; | |
131 | }; | |
132 | ||
133 | extern "C" Expression* | |
134 | script_exp_integer(uint64_t val) | |
135 | { | |
136 | return new Integer_expression(val); | |
137 | } | |
138 | ||
139 | // An expression whose value is the value of a symbol. | |
140 | ||
141 | class Symbol_expression : public Expression | |
142 | { | |
143 | public: | |
144 | Symbol_expression(const char* name, size_t length) | |
145 | : name_(name, length) | |
146 | { } | |
147 | ||
148 | uint64_t | |
149 | value(const Expression_eval_info*); | |
150 | ||
494e05f4 ILT |
151 | void |
152 | print(FILE* f) const | |
153 | { fprintf(f, "%s", this->name_.c_str()); } | |
154 | ||
e5756efb ILT |
155 | private: |
156 | std::string name_; | |
157 | }; | |
158 | ||
159 | uint64_t | |
160 | Symbol_expression::value(const Expression_eval_info* eei) | |
161 | { | |
162 | Symbol* sym = eei->symtab->lookup(this->name_.c_str()); | |
163 | if (sym == NULL || !sym->is_defined()) | |
164 | { | |
165 | gold_error(_("undefined symbol '%s' referenced in expression"), | |
166 | this->name_.c_str()); | |
167 | return 0; | |
168 | } | |
169 | ||
a445fddf ILT |
170 | // If this symbol does not have an absolute value, then the whole |
171 | // expression does not have an absolute value. This is not strictly | |
172 | // accurate: the subtraction of two symbols in the same section is | |
173 | // absolute. This is unlikely to matter in practice, as this value | |
174 | // is only used for error checking. | |
175 | if (!sym->value_is_absolute()) | |
176 | *eei->is_absolute = false; | |
177 | ||
e5756efb ILT |
178 | if (parameters->get_size() == 32) |
179 | return eei->symtab->get_sized_symbol<32>(sym)->value(); | |
180 | else if (parameters->get_size() == 64) | |
181 | return eei->symtab->get_sized_symbol<64>(sym)->value(); | |
182 | else | |
183 | gold_unreachable(); | |
184 | } | |
185 | ||
186 | // An expression whose value is the value of the special symbol ".". | |
187 | // This is only valid within a SECTIONS clause. | |
188 | ||
189 | class Dot_expression : public Expression | |
190 | { | |
191 | public: | |
192 | Dot_expression() | |
193 | { } | |
194 | ||
195 | uint64_t | |
196 | value(const Expression_eval_info*); | |
494e05f4 ILT |
197 | |
198 | void | |
199 | print(FILE* f) const | |
200 | { fprintf(f, "."); } | |
e5756efb ILT |
201 | }; |
202 | ||
203 | uint64_t | |
a445fddf | 204 | Dot_expression::value(const Expression_eval_info* eei) |
e5756efb | 205 | { |
a445fddf ILT |
206 | if (!eei->is_dot_available) |
207 | { | |
208 | gold_error(_("invalid reference to dot symbol outside of " | |
209 | "SECTIONS clause")); | |
210 | return 0; | |
211 | } | |
212 | else if (!eei->dot_has_value) | |
213 | { | |
214 | gold_error(_("invalid reference to dot symbol before " | |
215 | "it has been given a value")); | |
216 | return 0; | |
217 | } | |
218 | return eei->dot_value; | |
e5756efb ILT |
219 | } |
220 | ||
221 | // A string. This is either the name of a symbol, or ".". | |
222 | ||
223 | extern "C" Expression* | |
224 | script_exp_string(const char* name, size_t length) | |
225 | { | |
226 | if (length == 1 && name[0] == '.') | |
227 | return new Dot_expression(); | |
228 | else | |
229 | return new Symbol_expression(name, length); | |
230 | } | |
231 | ||
232 | // A unary expression. | |
233 | ||
234 | class Unary_expression : public Expression | |
235 | { | |
236 | public: | |
237 | Unary_expression(Expression* arg) | |
238 | : arg_(arg) | |
239 | { } | |
240 | ||
241 | ~Unary_expression() | |
242 | { delete this->arg_; } | |
243 | ||
244 | protected: | |
245 | uint64_t | |
246 | arg_value(const Expression_eval_info* eei) const | |
247 | { return this->arg_->value(eei); } | |
248 | ||
494e05f4 ILT |
249 | void |
250 | arg_print(FILE* f) const | |
251 | { this->arg_->print(f); } | |
252 | ||
e5756efb ILT |
253 | private: |
254 | Expression* arg_; | |
255 | }; | |
256 | ||
257 | // Handle unary operators. We use a preprocessor macro as a hack to | |
258 | // capture the C operator. | |
259 | ||
260 | #define UNARY_EXPRESSION(NAME, OPERATOR) \ | |
261 | class Unary_ ## NAME : public Unary_expression \ | |
262 | { \ | |
263 | public: \ | |
264 | Unary_ ## NAME(Expression* arg) \ | |
265 | : Unary_expression(arg) \ | |
266 | { } \ | |
267 | \ | |
268 | uint64_t \ | |
269 | value(const Expression_eval_info* eei) \ | |
270 | { return OPERATOR this->arg_value(eei); } \ | |
494e05f4 ILT |
271 | \ |
272 | void \ | |
273 | print(FILE* f) const \ | |
274 | { \ | |
275 | fprintf(f, "(%s ", #OPERATOR); \ | |
276 | this->arg_print(f); \ | |
277 | fprintf(f, ")"); \ | |
278 | } \ | |
e5756efb ILT |
279 | }; \ |
280 | \ | |
281 | extern "C" Expression* \ | |
282 | script_exp_unary_ ## NAME(Expression* arg) \ | |
283 | { \ | |
284 | return new Unary_ ## NAME(arg); \ | |
285 | } | |
286 | ||
287 | UNARY_EXPRESSION(minus, -) | |
288 | UNARY_EXPRESSION(logical_not, !) | |
289 | UNARY_EXPRESSION(bitwise_not, ~) | |
290 | ||
291 | // A binary expression. | |
292 | ||
293 | class Binary_expression : public Expression | |
294 | { | |
295 | public: | |
296 | Binary_expression(Expression* left, Expression* right) | |
297 | : left_(left), right_(right) | |
298 | { } | |
299 | ||
300 | ~Binary_expression() | |
301 | { | |
302 | delete this->left_; | |
303 | delete this->right_; | |
304 | } | |
305 | ||
306 | protected: | |
307 | uint64_t | |
308 | left_value(const Expression_eval_info* eei) const | |
309 | { return this->left_->value(eei); } | |
310 | ||
311 | uint64_t | |
312 | right_value(const Expression_eval_info* eei) const | |
313 | { return this->right_->value(eei); } | |
314 | ||
494e05f4 ILT |
315 | void |
316 | left_print(FILE* f) const | |
317 | { this->left_->print(f); } | |
318 | ||
319 | void | |
320 | right_print(FILE* f) const | |
321 | { this->right_->print(f); } | |
322 | ||
323 | // This is a call to function FUNCTION_NAME. Print it. This is for | |
324 | // debugging. | |
325 | void | |
326 | print_function(FILE* f, const char *function_name) const | |
327 | { | |
328 | fprintf(f, "%s(", function_name); | |
329 | this->left_print(f); | |
330 | fprintf(f, ", "); | |
331 | this->right_print(f); | |
332 | fprintf(f, ")"); | |
333 | } | |
334 | ||
e5756efb ILT |
335 | private: |
336 | Expression* left_; | |
337 | Expression* right_; | |
338 | }; | |
339 | ||
340 | // Handle binary operators. We use a preprocessor macro as a hack to | |
341 | // capture the C operator. | |
342 | ||
343 | #define BINARY_EXPRESSION(NAME, OPERATOR) \ | |
344 | class Binary_ ## NAME : public Binary_expression \ | |
345 | { \ | |
346 | public: \ | |
347 | Binary_ ## NAME(Expression* left, Expression* right) \ | |
348 | : Binary_expression(left, right) \ | |
349 | { } \ | |
350 | \ | |
351 | uint64_t \ | |
352 | value(const Expression_eval_info* eei) \ | |
353 | { \ | |
354 | return (this->left_value(eei) \ | |
355 | OPERATOR this->right_value(eei)); \ | |
494e05f4 ILT |
356 | } \ |
357 | \ | |
358 | void \ | |
359 | print(FILE* f) const \ | |
360 | { \ | |
361 | fprintf(f, "("); \ | |
362 | this->left_print(f); \ | |
363 | fprintf(f, " %s ", #OPERATOR); \ | |
364 | this->right_print(f); \ | |
365 | fprintf(f, ")"); \ | |
e5756efb ILT |
366 | } \ |
367 | }; \ | |
368 | \ | |
369 | extern "C" Expression* \ | |
370 | script_exp_binary_ ## NAME(Expression* left, Expression* right) \ | |
371 | { \ | |
372 | return new Binary_ ## NAME(left, right); \ | |
373 | } | |
374 | ||
375 | BINARY_EXPRESSION(mult, *) | |
376 | BINARY_EXPRESSION(div, /) | |
377 | BINARY_EXPRESSION(mod, %) | |
378 | BINARY_EXPRESSION(add, +) | |
379 | BINARY_EXPRESSION(sub, -) | |
380 | BINARY_EXPRESSION(lshift, <<) | |
381 | BINARY_EXPRESSION(rshift, >>) | |
382 | BINARY_EXPRESSION(eq, ==) | |
383 | BINARY_EXPRESSION(ne, !=) | |
384 | BINARY_EXPRESSION(le, <=) | |
385 | BINARY_EXPRESSION(ge, >=) | |
386 | BINARY_EXPRESSION(lt, <) | |
387 | BINARY_EXPRESSION(gt, >) | |
388 | BINARY_EXPRESSION(bitwise_and, &) | |
389 | BINARY_EXPRESSION(bitwise_xor, ^) | |
390 | BINARY_EXPRESSION(bitwise_or, |) | |
391 | BINARY_EXPRESSION(logical_and, &&) | |
392 | BINARY_EXPRESSION(logical_or, ||) | |
393 | ||
394 | // A trinary expression. | |
395 | ||
396 | class Trinary_expression : public Expression | |
397 | { | |
398 | public: | |
399 | Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3) | |
400 | : arg1_(arg1), arg2_(arg2), arg3_(arg3) | |
401 | { } | |
402 | ||
403 | ~Trinary_expression() | |
404 | { | |
405 | delete this->arg1_; | |
406 | delete this->arg2_; | |
407 | delete this->arg3_; | |
408 | } | |
409 | ||
410 | protected: | |
411 | uint64_t | |
412 | arg1_value(const Expression_eval_info* eei) const | |
413 | { return this->arg1_->value(eei); } | |
414 | ||
415 | uint64_t | |
416 | arg2_value(const Expression_eval_info* eei) const | |
417 | { return this->arg2_->value(eei); } | |
418 | ||
419 | uint64_t | |
420 | arg3_value(const Expression_eval_info* eei) const | |
421 | { return this->arg3_->value(eei); } | |
422 | ||
494e05f4 ILT |
423 | void |
424 | arg1_print(FILE* f) const | |
425 | { this->arg1_->print(f); } | |
426 | ||
427 | void | |
428 | arg2_print(FILE* f) const | |
429 | { this->arg2_->print(f); } | |
430 | ||
431 | void | |
432 | arg3_print(FILE* f) const | |
433 | { this->arg3_->print(f); } | |
434 | ||
e5756efb ILT |
435 | private: |
436 | Expression* arg1_; | |
437 | Expression* arg2_; | |
438 | Expression* arg3_; | |
439 | }; | |
440 | ||
441 | // The conditional operator. | |
442 | ||
443 | class Trinary_cond : public Trinary_expression | |
444 | { | |
445 | public: | |
446 | Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
447 | : Trinary_expression(arg1, arg2, arg3) | |
448 | { } | |
449 | ||
450 | uint64_t | |
451 | value(const Expression_eval_info* eei) | |
452 | { | |
453 | return (this->arg1_value(eei) | |
454 | ? this->arg2_value(eei) | |
455 | : this->arg3_value(eei)); | |
456 | } | |
494e05f4 ILT |
457 | |
458 | void | |
459 | print(FILE* f) const | |
460 | { | |
461 | fprintf(f, "("); | |
462 | this->arg1_print(f); | |
463 | fprintf(f, " ? "); | |
464 | this->arg2_print(f); | |
465 | fprintf(f, " : "); | |
466 | this->arg3_print(f); | |
467 | fprintf(f, ")"); | |
468 | } | |
e5756efb ILT |
469 | }; |
470 | ||
471 | extern "C" Expression* | |
472 | script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) | |
473 | { | |
474 | return new Trinary_cond(arg1, arg2, arg3); | |
475 | } | |
476 | ||
477 | // Max function. | |
478 | ||
479 | class Max_expression : public Binary_expression | |
480 | { | |
481 | public: | |
482 | Max_expression(Expression* left, Expression* right) | |
483 | : Binary_expression(left, right) | |
484 | { } | |
485 | ||
486 | uint64_t | |
487 | value(const Expression_eval_info* eei) | |
488 | { return std::max(this->left_value(eei), this->right_value(eei)); } | |
494e05f4 ILT |
489 | |
490 | void | |
491 | print(FILE* f) const | |
492 | { this->print_function(f, "MAX"); } | |
e5756efb ILT |
493 | }; |
494 | ||
495 | extern "C" Expression* | |
496 | script_exp_function_max(Expression* left, Expression* right) | |
497 | { | |
498 | return new Max_expression(left, right); | |
499 | } | |
500 | ||
501 | // Min function. | |
502 | ||
503 | class Min_expression : public Binary_expression | |
504 | { | |
505 | public: | |
506 | Min_expression(Expression* left, Expression* right) | |
507 | : Binary_expression(left, right) | |
508 | { } | |
509 | ||
510 | uint64_t | |
511 | value(const Expression_eval_info* eei) | |
512 | { return std::min(this->left_value(eei), this->right_value(eei)); } | |
494e05f4 ILT |
513 | |
514 | void | |
515 | print(FILE* f) const | |
516 | { this->print_function(f, "MIN"); } | |
e5756efb ILT |
517 | }; |
518 | ||
519 | extern "C" Expression* | |
520 | script_exp_function_min(Expression* left, Expression* right) | |
521 | { | |
522 | return new Min_expression(left, right); | |
523 | } | |
524 | ||
525 | // Align function. | |
526 | ||
527 | class Align_expression : public Binary_expression | |
528 | { | |
529 | public: | |
530 | Align_expression(Expression* left, Expression* right) | |
531 | : Binary_expression(left, right) | |
532 | { } | |
533 | ||
534 | uint64_t | |
535 | value(const Expression_eval_info* eei) | |
536 | { | |
537 | uint64_t align = this->right_value(eei); | |
538 | uint64_t value = this->left_value(eei); | |
539 | if (align <= 1) | |
540 | return value; | |
541 | return ((value + align - 1) / align) * align; | |
542 | } | |
494e05f4 ILT |
543 | |
544 | void | |
545 | print(FILE* f) const | |
546 | { this->print_function(f, "ALIGN"); } | |
e5756efb ILT |
547 | }; |
548 | ||
549 | extern "C" Expression* | |
550 | script_exp_function_align(Expression* left, Expression* right) | |
551 | { | |
552 | return new Align_expression(left, right); | |
553 | } | |
554 | ||
555 | // Assert function. | |
556 | ||
557 | class Assert_expression : public Unary_expression | |
558 | { | |
559 | public: | |
560 | Assert_expression(Expression* arg, const char* message, size_t length) | |
561 | : Unary_expression(arg), message_(message, length) | |
562 | { } | |
563 | ||
564 | uint64_t | |
565 | value(const Expression_eval_info* eei) | |
566 | { | |
567 | uint64_t value = this->arg_value(eei); | |
568 | if (!value) | |
569 | gold_error("%s", this->message_.c_str()); | |
570 | return value; | |
571 | } | |
572 | ||
494e05f4 ILT |
573 | void |
574 | print(FILE* f) const | |
575 | { | |
576 | fprintf(f, "ASSERT("); | |
577 | this->arg_print(f); | |
578 | fprintf(f, ", %s)", this->message_.c_str()); | |
579 | } | |
580 | ||
e5756efb ILT |
581 | private: |
582 | std::string message_; | |
583 | }; | |
584 | ||
585 | extern "C" Expression* | |
586 | script_exp_function_assert(Expression* expr, const char* message, | |
587 | size_t length) | |
588 | { | |
589 | return new Assert_expression(expr, message, length); | |
590 | } | |
591 | ||
494e05f4 ILT |
592 | // Addr function. |
593 | ||
594 | class Addr_expression : public Expression | |
595 | { | |
596 | public: | |
597 | Addr_expression(const char* section_name, size_t section_name_len) | |
598 | : section_name_(section_name, section_name_len) | |
599 | { } | |
600 | ||
601 | uint64_t | |
602 | value(const Expression_eval_info*); | |
603 | ||
604 | void | |
605 | print(FILE* f) const | |
606 | { fprintf(f, "ADDR(%s)", this->section_name_.c_str()); } | |
607 | ||
608 | private: | |
609 | std::string section_name_; | |
610 | }; | |
611 | ||
612 | uint64_t | |
613 | Addr_expression::value(const Expression_eval_info* eei) | |
614 | { | |
615 | const char* section_name = this->section_name_.c_str(); | |
616 | Output_section* os = eei->layout->find_output_section(section_name); | |
617 | if (os == NULL) | |
618 | { | |
619 | gold_error("ADDR called on nonexistent output section '%s'", | |
620 | section_name); | |
621 | return 0; | |
622 | } | |
a445fddf ILT |
623 | |
624 | // Note that the address of a section is an absolute address, and we | |
625 | // should not clear *EEI->IS_ABSOLUTE here. | |
626 | ||
494e05f4 ILT |
627 | return os->address(); |
628 | } | |
629 | ||
630 | extern "C" Expression* | |
631 | script_exp_function_addr(const char* section_name, size_t section_name_len) | |
632 | { | |
633 | return new Addr_expression(section_name, section_name_len); | |
634 | } | |
635 | ||
3802b2dd ILT |
636 | // CONSTANT. It would be nice if we could simply evaluate this |
637 | // immediately and return an Integer_expression, but unfortunately we | |
638 | // don't know the target. | |
639 | ||
640 | class Constant_expression : public Expression | |
641 | { | |
642 | public: | |
643 | Constant_expression(const char* name, size_t length); | |
644 | ||
645 | uint64_t | |
646 | value(const Expression_eval_info*); | |
647 | ||
648 | void | |
649 | print(FILE* f) const; | |
650 | ||
651 | private: | |
652 | enum Constant_function | |
653 | { | |
654 | CONSTANT_MAXPAGESIZE, | |
655 | CONSTANT_COMMONPAGESIZE | |
656 | }; | |
e5756efb | 657 | |
3802b2dd ILT |
658 | Constant_function function_; |
659 | }; | |
660 | ||
661 | Constant_expression::Constant_expression(const char* name, size_t length) | |
662 | { | |
663 | if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) | |
664 | this->function_ = CONSTANT_MAXPAGESIZE; | |
665 | else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) | |
666 | this->function_ = CONSTANT_COMMONPAGESIZE; | |
667 | else | |
668 | { | |
669 | std::string s(name, length); | |
670 | gold_error(_("unknown constant %s"), s.c_str()); | |
671 | this->function_ = CONSTANT_MAXPAGESIZE; | |
672 | } | |
673 | } | |
674 | ||
675 | uint64_t | |
676 | Constant_expression::value(const Expression_eval_info*) | |
677 | { | |
678 | switch (this->function_) | |
679 | { | |
680 | case CONSTANT_MAXPAGESIZE: | |
681 | return parameters->target()->abi_pagesize(); | |
682 | case CONSTANT_COMMONPAGESIZE: | |
683 | return parameters->target()->common_pagesize(); | |
684 | default: | |
685 | gold_unreachable(); | |
686 | } | |
687 | } | |
688 | ||
689 | void | |
690 | Constant_expression::print(FILE* f) const | |
691 | { | |
692 | const char* name; | |
693 | switch (this->function_) | |
694 | { | |
695 | case CONSTANT_MAXPAGESIZE: | |
696 | name = "MAXPAGESIZE"; | |
697 | break; | |
698 | case CONSTANT_COMMONPAGESIZE: | |
699 | name = "COMMONPAGESIZE"; | |
700 | break; | |
701 | default: | |
702 | gold_unreachable(); | |
703 | } | |
704 | fprintf(f, "CONSTANT(%s)", name); | |
705 | } | |
706 | ||
e5756efb | 707 | extern "C" Expression* |
3802b2dd | 708 | script_exp_function_constant(const char* name, size_t length) |
e5756efb | 709 | { |
3802b2dd | 710 | return new Constant_expression(name, length); |
e5756efb ILT |
711 | } |
712 | ||
3802b2dd ILT |
713 | // DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall |
714 | // back to the general case. | |
715 | ||
e5756efb | 716 | extern "C" Expression* |
3802b2dd | 717 | script_exp_function_data_segment_align(Expression* left, Expression*) |
e5756efb | 718 | { |
3802b2dd ILT |
719 | Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); |
720 | Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); | |
721 | Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), | |
722 | e2); | |
723 | return script_exp_binary_add(e1, e3); | |
e5756efb ILT |
724 | } |
725 | ||
3802b2dd ILT |
726 | // DATA_SEGMENT_RELRO. FIXME: This is not implemented. |
727 | ||
e5756efb | 728 | extern "C" Expression* |
3802b2dd | 729 | script_exp_function_data_segment_relro_end(Expression*, Expression* right) |
e5756efb | 730 | { |
3802b2dd | 731 | return right; |
e5756efb ILT |
732 | } |
733 | ||
3802b2dd ILT |
734 | // DATA_SEGMENT_END. FIXME: This is not implemented. |
735 | ||
e5756efb | 736 | extern "C" Expression* |
3802b2dd | 737 | script_exp_function_data_segment_end(Expression* val) |
e5756efb | 738 | { |
3802b2dd ILT |
739 | return val; |
740 | } | |
741 | ||
742 | // SIZEOF_HEADERS. | |
743 | ||
744 | class Sizeof_headers_expression : public Expression | |
745 | { | |
746 | public: | |
747 | Sizeof_headers_expression() | |
748 | { } | |
749 | ||
750 | uint64_t | |
751 | value(const Expression_eval_info*); | |
752 | ||
753 | void | |
754 | print(FILE* f) const | |
755 | { fprintf(f, "SIZEOF_HEADERS"); } | |
756 | }; | |
757 | ||
758 | uint64_t | |
759 | Sizeof_headers_expression::value(const Expression_eval_info* eei) | |
760 | { | |
761 | unsigned int ehdr_size; | |
762 | unsigned int phdr_size; | |
763 | if (parameters->get_size() == 32) | |
764 | { | |
765 | ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; | |
766 | phdr_size = elfcpp::Elf_sizes<32>::phdr_size; | |
767 | } | |
768 | else if (parameters->get_size() == 64) | |
769 | { | |
770 | ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; | |
771 | phdr_size = elfcpp::Elf_sizes<64>::phdr_size; | |
772 | } | |
773 | else | |
774 | gold_unreachable(); | |
775 | ||
776 | return ehdr_size + phdr_size * eei->layout->expected_segment_count(); | |
e5756efb ILT |
777 | } |
778 | ||
e5756efb | 779 | extern "C" Expression* |
3802b2dd | 780 | script_exp_function_sizeof_headers() |
e5756efb | 781 | { |
3802b2dd | 782 | return new Sizeof_headers_expression(); |
e5756efb ILT |
783 | } |
784 | ||
3802b2dd ILT |
785 | // Functions. |
786 | ||
e5756efb | 787 | extern "C" Expression* |
3802b2dd | 788 | script_exp_function_defined(const char*, size_t) |
e5756efb | 789 | { |
3802b2dd | 790 | gold_fatal(_("DEFINED not implemented")); |
e5756efb ILT |
791 | } |
792 | ||
793 | extern "C" Expression* | |
3802b2dd | 794 | script_exp_function_alignof(const char*, size_t) |
e5756efb | 795 | { |
3802b2dd | 796 | gold_fatal(_("ALIGNOF not implemented")); |
e5756efb ILT |
797 | } |
798 | ||
799 | extern "C" Expression* | |
3802b2dd | 800 | script_exp_function_sizeof(const char*, size_t) |
e5756efb | 801 | { |
3802b2dd | 802 | gold_fatal(_("SIZEOF not implemented")); |
e5756efb ILT |
803 | } |
804 | ||
805 | extern "C" Expression* | |
3802b2dd | 806 | script_exp_function_loadaddr(const char*, size_t) |
e5756efb | 807 | { |
3802b2dd | 808 | gold_fatal(_("LOADADDR not implemented")); |
e5756efb ILT |
809 | } |
810 | ||
811 | extern "C" Expression* | |
3802b2dd | 812 | script_exp_function_origin(const char*, size_t) |
e5756efb | 813 | { |
3802b2dd | 814 | gold_fatal(_("ORIGIN not implemented")); |
e5756efb ILT |
815 | } |
816 | ||
817 | extern "C" Expression* | |
3802b2dd | 818 | script_exp_function_length(const char*, size_t) |
e5756efb | 819 | { |
3802b2dd | 820 | gold_fatal(_("LENGTH not implemented")); |
e5756efb ILT |
821 | } |
822 | ||
823 | extern "C" Expression* | |
3802b2dd | 824 | script_exp_function_absolute(Expression*) |
e5756efb | 825 | { |
3802b2dd | 826 | gold_fatal(_("ABSOLUTE not implemented")); |
e5756efb ILT |
827 | } |
828 | ||
829 | extern "C" Expression* | |
830 | script_exp_function_segment_start(const char*, size_t, Expression*) | |
831 | { | |
832 | gold_fatal(_("SEGMENT_START not implemented")); | |
833 | } | |
834 | ||
835 | } // End namespace gold. |