Commit | Line | Data |
---|---|---|
494e05f4 ILT |
1 | // script-sections.cc -- linker script SECTIONS for gold |
2 | ||
3 | // Copyright 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 | #include <vector> | |
27 | ||
28 | #include "script-c.h" | |
29 | #include "script.h" | |
30 | #include "script-sections.h" | |
31 | ||
32 | // Support for the SECTIONS clause in linker scripts. | |
33 | ||
34 | namespace gold | |
35 | { | |
36 | ||
37 | // An element in a SECTIONS clause. | |
38 | ||
39 | class Sections_element | |
40 | { | |
41 | public: | |
42 | Sections_element() | |
43 | { } | |
44 | ||
45 | virtual ~Sections_element() | |
46 | { } | |
47 | ||
48 | virtual void | |
49 | print(FILE* f) const = 0; | |
50 | }; | |
51 | ||
52 | // An assignment in a SECTIONS clause outside of an output section. | |
53 | ||
54 | class Sections_element_assignment : public Sections_element | |
55 | { | |
56 | public: | |
57 | Sections_element_assignment(const char* name, size_t namelen, | |
58 | Expression* val, bool provide, bool hidden) | |
59 | : assignment_(name, namelen, val, provide, hidden) | |
60 | { } | |
61 | ||
62 | void | |
63 | print(FILE* f) const | |
64 | { | |
65 | fprintf(f, " "); | |
66 | this->assignment_.print(f); | |
67 | } | |
68 | ||
69 | private: | |
70 | Symbol_assignment assignment_; | |
71 | }; | |
72 | ||
73 | // An assertion in a SECTIONS clause outside of an output section. | |
74 | ||
75 | class Sections_element_assertion : public Sections_element | |
76 | { | |
77 | public: | |
78 | Sections_element_assertion(Expression* check, const char* message, | |
79 | size_t messagelen) | |
80 | : assertion_(check, message, messagelen) | |
81 | { } | |
82 | ||
83 | void | |
84 | print(FILE* f) const | |
85 | { | |
86 | fprintf(f, " "); | |
87 | this->assertion_.print(f); | |
88 | } | |
89 | ||
90 | private: | |
91 | Script_assertion assertion_; | |
92 | }; | |
93 | ||
94 | // An element in an output section in a SECTIONS clause. | |
95 | ||
96 | class Output_section_element | |
97 | { | |
98 | public: | |
99 | Output_section_element() | |
100 | { } | |
101 | ||
102 | virtual ~Output_section_element() | |
103 | { } | |
104 | ||
105 | virtual void | |
106 | print(FILE* f) const = 0; | |
107 | }; | |
108 | ||
109 | // A symbol assignment in an output section. | |
110 | ||
111 | class Output_section_element_assignment : public Output_section_element | |
112 | { | |
113 | public: | |
114 | Output_section_element_assignment(const char* name, size_t namelen, | |
115 | Expression* val, bool provide, | |
116 | bool hidden) | |
117 | : assignment_(name, namelen, val, provide, hidden) | |
118 | { } | |
119 | ||
120 | void | |
121 | print(FILE* f) const | |
122 | { | |
123 | fprintf(f, " "); | |
124 | this->assignment_.print(f); | |
125 | } | |
126 | ||
127 | private: | |
128 | Symbol_assignment assignment_; | |
129 | }; | |
130 | ||
131 | // An assertion in an output section. | |
132 | ||
133 | class Output_section_element_assertion : public Output_section_element | |
134 | { | |
135 | public: | |
136 | Output_section_element_assertion(Expression* check, const char* message, | |
137 | size_t messagelen) | |
138 | : assertion_(check, message, messagelen) | |
139 | { } | |
140 | ||
141 | void | |
142 | print(FILE* f) const | |
143 | { | |
144 | fprintf(f, " "); | |
145 | this->assertion_.print(f); | |
146 | } | |
147 | ||
148 | private: | |
149 | Script_assertion assertion_; | |
150 | }; | |
151 | ||
152 | // A data item in an output section. | |
153 | ||
154 | class Output_section_element_data : public Output_section_element | |
155 | { | |
156 | public: | |
157 | Output_section_element_data(int size, bool is_signed, Expression* val) | |
158 | : size_(size), is_signed_(is_signed), val_(val) | |
159 | { } | |
160 | ||
161 | void | |
162 | print(FILE*) const; | |
163 | ||
164 | private: | |
165 | // The size in bytes. | |
166 | int size_; | |
167 | // Whether the value is signed. | |
168 | bool is_signed_; | |
169 | // The value. | |
170 | Expression* val_; | |
171 | }; | |
172 | ||
173 | // Print for debugging. | |
174 | ||
175 | void | |
176 | Output_section_element_data::print(FILE* f) const | |
177 | { | |
178 | const char* s; | |
179 | switch (this->size_) | |
180 | { | |
181 | case 1: | |
182 | s = "BYTE"; | |
183 | break; | |
184 | case 2: | |
185 | s = "SHORT"; | |
186 | break; | |
187 | case 4: | |
188 | s = "LONG"; | |
189 | break; | |
190 | case 8: | |
191 | if (this->is_signed_) | |
192 | s = "SQUAD"; | |
193 | else | |
194 | s = "QUAD"; | |
195 | break; | |
196 | default: | |
197 | gold_unreachable(); | |
198 | } | |
199 | fprintf(f, " %s(", s); | |
200 | this->val_->print(f); | |
201 | fprintf(f, ")\n"); | |
202 | } | |
203 | ||
204 | // A fill value setting in an output section. | |
205 | ||
206 | class Output_section_element_fill : public Output_section_element | |
207 | { | |
208 | public: | |
209 | Output_section_element_fill(Expression* val) | |
210 | : val_(val) | |
211 | { } | |
212 | ||
213 | void | |
214 | print(FILE* f) const | |
215 | { | |
216 | fprintf(f, " FILL("); | |
217 | this->val_->print(f); | |
218 | fprintf(f, ")\n"); | |
219 | } | |
220 | ||
221 | private: | |
222 | // The new fill value. | |
223 | Expression* val_; | |
224 | }; | |
225 | ||
226 | // An input section specification in an output section | |
227 | ||
228 | class Output_section_element_input : public Output_section_element | |
229 | { | |
230 | public: | |
231 | // Note that an Input_section_spec holds some pointers to vectors. | |
232 | // This constructor takes ownership of them. The parser is | |
233 | // implemented such that this works. | |
234 | Output_section_element_input(const Input_section_spec* spec, bool keep); | |
235 | ||
236 | void | |
237 | print(FILE* f) const; | |
238 | ||
239 | private: | |
240 | // An input section pattern. | |
241 | struct Input_section_pattern | |
242 | { | |
243 | std::string pattern; | |
244 | Sort_wildcard sort; | |
245 | ||
246 | Input_section_pattern(const char* patterna, size_t patternlena, | |
247 | Sort_wildcard sorta) | |
248 | : pattern(patterna, patternlena), sort(sorta) | |
249 | { } | |
250 | }; | |
251 | ||
252 | typedef std::vector<Input_section_pattern> Input_section_patterns; | |
253 | ||
254 | typedef std::vector<std::string> Filename_exclusions; | |
255 | ||
256 | // The file name pattern. | |
257 | std::string filename_pattern_; | |
258 | // How the file names should be sorted. This may only be | |
259 | // SORT_WILDCARD_NONE or SORT_WILDCARD_BY_NAME. | |
260 | Sort_wildcard filename_sort_; | |
261 | // The list of file names to exclude. | |
262 | Filename_exclusions filename_exclusions_; | |
263 | // The list of input section patterns. | |
264 | Input_section_patterns input_section_patterns_; | |
265 | // Whether to keep this section when garbage collecting. | |
266 | bool keep_; | |
267 | }; | |
268 | ||
269 | // Construct Output_section_element_input. The parser records strings | |
270 | // as pointers into a copy of the script file, which will go away when | |
271 | // parsing is complete. We make sure they are in std::string objects. | |
272 | ||
273 | Output_section_element_input::Output_section_element_input( | |
274 | const Input_section_spec* spec, | |
275 | bool keep) | |
276 | : filename_pattern_(spec->file.name.value, spec->file.name.length), | |
277 | filename_sort_(spec->file.sort), | |
278 | filename_exclusions_(), | |
279 | input_section_patterns_(), | |
280 | keep_(keep) | |
281 | { | |
282 | if (spec->input_sections.exclude != NULL) | |
283 | { | |
284 | for (String_list::const_iterator p = | |
285 | spec->input_sections.exclude->begin(); | |
286 | p != spec->input_sections.exclude->end(); | |
287 | ++p) | |
288 | this->filename_exclusions_.push_back(*p); | |
289 | } | |
290 | ||
291 | if (spec->input_sections.sections != NULL) | |
292 | { | |
293 | Input_section_patterns& isp(this->input_section_patterns_); | |
294 | for (String_sort_list::const_iterator p = | |
295 | spec->input_sections.sections->begin(); | |
296 | p != spec->input_sections.sections->end(); | |
297 | ++p) | |
298 | isp.push_back(Input_section_pattern(p->name.value, p->name.length, | |
299 | p->sort)); | |
300 | } | |
301 | } | |
302 | ||
303 | // Print for debugging. | |
304 | ||
305 | void | |
306 | Output_section_element_input::print(FILE* f) const | |
307 | { | |
308 | fprintf(f, " "); | |
309 | ||
310 | if (this->keep_) | |
311 | fprintf(f, "KEEP("); | |
312 | ||
313 | if (!this->filename_pattern_.empty()) | |
314 | { | |
315 | bool need_close_paren = false; | |
316 | switch (this->filename_sort_) | |
317 | { | |
318 | case SORT_WILDCARD_NONE: | |
319 | break; | |
320 | case SORT_WILDCARD_BY_NAME: | |
321 | fprintf(f, "SORT_BY_NAME("); | |
322 | need_close_paren = true; | |
323 | break; | |
324 | default: | |
325 | gold_unreachable(); | |
326 | } | |
327 | ||
328 | fprintf(f, "%s", this->filename_pattern_.c_str()); | |
329 | ||
330 | if (need_close_paren) | |
331 | fprintf(f, ")"); | |
332 | } | |
333 | ||
334 | if (!this->input_section_patterns_.empty() | |
335 | || !this->filename_exclusions_.empty()) | |
336 | { | |
337 | fprintf(f, "("); | |
338 | ||
339 | bool need_space = false; | |
340 | if (!this->filename_exclusions_.empty()) | |
341 | { | |
342 | fprintf(f, "EXCLUDE_FILE("); | |
343 | bool need_comma = false; | |
344 | for (Filename_exclusions::const_iterator p = | |
345 | this->filename_exclusions_.begin(); | |
346 | p != this->filename_exclusions_.end(); | |
347 | ++p) | |
348 | { | |
349 | if (need_comma) | |
350 | fprintf(f, ", "); | |
351 | fprintf(f, "%s", p->c_str()); | |
352 | need_comma = true; | |
353 | } | |
354 | fprintf(f, ")"); | |
355 | need_space = true; | |
356 | } | |
357 | ||
358 | for (Input_section_patterns::const_iterator p = | |
359 | this->input_section_patterns_.begin(); | |
360 | p != this->input_section_patterns_.end(); | |
361 | ++p) | |
362 | { | |
363 | if (need_space) | |
364 | fprintf(f, " "); | |
365 | ||
366 | int close_parens = 0; | |
367 | switch (p->sort) | |
368 | { | |
369 | case SORT_WILDCARD_NONE: | |
370 | break; | |
371 | case SORT_WILDCARD_BY_NAME: | |
372 | fprintf(f, "SORT_BY_NAME("); | |
373 | close_parens = 1; | |
374 | break; | |
375 | case SORT_WILDCARD_BY_ALIGNMENT: | |
376 | fprintf(f, "SORT_BY_ALIGNMENT("); | |
377 | close_parens = 1; | |
378 | break; | |
379 | case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT: | |
380 | fprintf(f, "SORT_BY_NAME(SORT_BY_ALIGNMENT("); | |
381 | close_parens = 2; | |
382 | break; | |
383 | case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME: | |
384 | fprintf(f, "SORT_BY_ALIGNMENT(SORT_BY_NAME("); | |
385 | close_parens = 2; | |
386 | break; | |
387 | default: | |
388 | gold_unreachable(); | |
389 | } | |
390 | ||
391 | fprintf(f, "%s", p->pattern.c_str()); | |
392 | ||
393 | for (int i = 0; i < close_parens; ++i) | |
394 | fprintf(f, ")"); | |
395 | ||
396 | need_space = true; | |
397 | } | |
398 | ||
399 | fprintf(f, ")"); | |
400 | } | |
401 | ||
402 | if (this->keep_) | |
403 | fprintf(f, ")"); | |
404 | ||
405 | fprintf(f, "\n"); | |
406 | } | |
407 | ||
408 | // An output section. | |
409 | ||
410 | class Output_section_definition : public Sections_element | |
411 | { | |
412 | public: | |
413 | Output_section_definition(const char* name, size_t namelen, | |
414 | const Parser_output_section_header* header); | |
415 | ||
416 | // Finish the output section with the information in the trailer. | |
417 | void | |
418 | finish(const Parser_output_section_trailer* trailer); | |
419 | ||
420 | // Add a symbol to be defined. | |
421 | void | |
422 | add_symbol_assignment(const char* name, size_t length, Expression* value, | |
423 | bool provide, bool hidden); | |
424 | // Add an assertion. | |
425 | void | |
426 | add_assertion(Expression* check, const char* message, size_t messagelen); | |
427 | ||
428 | // Add a data item to the current output section. | |
429 | void | |
430 | add_data(int size, bool is_signed, Expression* val); | |
431 | ||
432 | // Add a setting for the fill value. | |
433 | void | |
434 | add_fill(Expression* val); | |
435 | ||
436 | // Add an input section specification. | |
437 | void | |
438 | add_input_section(const Input_section_spec* spec, bool keep); | |
439 | ||
440 | // Print the contents to the FILE. This is for debugging. | |
441 | void | |
442 | print(FILE*) const; | |
443 | ||
444 | private: | |
445 | typedef std::vector<Output_section_element*> Output_section_elements; | |
446 | ||
447 | // The output section name. | |
448 | std::string name_; | |
449 | // The address. This may be NULL. | |
450 | Expression* address_; | |
451 | // The load address. This may be NULL. | |
452 | Expression* load_address_; | |
453 | // The alignment. This may be NULL. | |
454 | Expression* align_; | |
455 | // The input section alignment. This may be NULL. | |
456 | Expression* subalign_; | |
457 | // The fill value. This may be NULL. | |
458 | Expression* fill_; | |
459 | // The list of elements defining the section. | |
460 | Output_section_elements elements_; | |
461 | }; | |
462 | ||
463 | // Constructor. | |
464 | ||
465 | Output_section_definition::Output_section_definition( | |
466 | const char* name, | |
467 | size_t namelen, | |
468 | const Parser_output_section_header* header) | |
469 | : name_(name, namelen), | |
470 | address_(header->address), | |
471 | load_address_(header->load_address), | |
472 | align_(header->align), | |
473 | subalign_(header->subalign), | |
474 | fill_(NULL), | |
475 | elements_() | |
476 | { | |
477 | } | |
478 | ||
479 | // Finish an output section. | |
480 | ||
481 | void | |
482 | Output_section_definition::finish(const Parser_output_section_trailer* trailer) | |
483 | { | |
484 | this->fill_ = trailer->fill; | |
485 | } | |
486 | ||
487 | // Add a symbol to be defined. | |
488 | ||
489 | void | |
490 | Output_section_definition::add_symbol_assignment(const char* name, | |
491 | size_t length, | |
492 | Expression* value, | |
493 | bool provide, | |
494 | bool hidden) | |
495 | { | |
496 | Output_section_element* p = new Output_section_element_assignment(name, | |
497 | length, | |
498 | value, | |
499 | provide, | |
500 | hidden); | |
501 | this->elements_.push_back(p); | |
502 | } | |
503 | ||
504 | // Add an assertion. | |
505 | ||
506 | void | |
507 | Output_section_definition::add_assertion(Expression* check, | |
508 | const char* message, | |
509 | size_t messagelen) | |
510 | { | |
511 | Output_section_element* p = new Output_section_element_assertion(check, | |
512 | message, | |
513 | messagelen); | |
514 | this->elements_.push_back(p); | |
515 | } | |
516 | ||
517 | // Add a data item to the current output section. | |
518 | ||
519 | void | |
520 | Output_section_definition::add_data(int size, bool is_signed, Expression* val) | |
521 | { | |
522 | Output_section_element* p = new Output_section_element_data(size, is_signed, | |
523 | val); | |
524 | this->elements_.push_back(p); | |
525 | } | |
526 | ||
527 | // Add a setting for the fill value. | |
528 | ||
529 | void | |
530 | Output_section_definition::add_fill(Expression* val) | |
531 | { | |
532 | Output_section_element* p = new Output_section_element_fill(val); | |
533 | this->elements_.push_back(p); | |
534 | } | |
535 | ||
536 | // Add an input section specification. | |
537 | ||
538 | void | |
539 | Output_section_definition::add_input_section(const Input_section_spec* spec, | |
540 | bool keep) | |
541 | { | |
542 | Output_section_element* p = new Output_section_element_input(spec, keep); | |
543 | this->elements_.push_back(p); | |
544 | } | |
545 | ||
546 | // Print for debugging. | |
547 | ||
548 | void | |
549 | Output_section_definition::print(FILE* f) const | |
550 | { | |
551 | fprintf(f, " %s ", this->name_.c_str()); | |
552 | ||
553 | if (this->address_ != NULL) | |
554 | { | |
555 | this->address_->print(f); | |
556 | fprintf(f, " "); | |
557 | } | |
558 | ||
559 | fprintf(f, ": "); | |
560 | ||
561 | if (this->load_address_ != NULL) | |
562 | { | |
563 | fprintf(f, "AT("); | |
564 | this->load_address_->print(f); | |
565 | fprintf(f, ") "); | |
566 | } | |
567 | ||
568 | if (this->align_ != NULL) | |
569 | { | |
570 | fprintf(f, "ALIGN("); | |
571 | this->align_->print(f); | |
572 | fprintf(f, ") "); | |
573 | } | |
574 | ||
575 | if (this->subalign_ != NULL) | |
576 | { | |
577 | fprintf(f, "SUBALIGN("); | |
578 | this->subalign_->print(f); | |
579 | fprintf(f, ") "); | |
580 | } | |
581 | ||
582 | fprintf(f, "{\n"); | |
583 | ||
584 | for (Output_section_elements::const_iterator p = this->elements_.begin(); | |
585 | p != this->elements_.end(); | |
586 | ++p) | |
587 | (*p)->print(f); | |
588 | ||
589 | fprintf(f, " }"); | |
590 | ||
591 | if (this->fill_ != NULL) | |
592 | { | |
593 | fprintf(f, " = "); | |
594 | this->fill_->print(f); | |
595 | } | |
596 | ||
597 | fprintf(f, "\n"); | |
598 | } | |
599 | ||
600 | // Class Script_sections. | |
601 | ||
602 | Script_sections::Script_sections() | |
603 | : saw_sections_clause_(false), | |
604 | in_sections_clause_(false), | |
605 | sections_elements_(NULL), | |
606 | output_section_(NULL) | |
607 | { | |
608 | } | |
609 | ||
610 | // Start a SECTIONS clause. | |
611 | ||
612 | void | |
613 | Script_sections::start_sections() | |
614 | { | |
615 | gold_assert(!this->in_sections_clause_ && this->output_section_ == NULL); | |
616 | this->saw_sections_clause_ = true; | |
617 | this->in_sections_clause_ = true; | |
618 | if (this->sections_elements_ == NULL) | |
619 | this->sections_elements_ = new Sections_elements; | |
620 | } | |
621 | ||
622 | // Finish a SECTIONS clause. | |
623 | ||
624 | void | |
625 | Script_sections::finish_sections() | |
626 | { | |
627 | gold_assert(this->in_sections_clause_ && this->output_section_ == NULL); | |
628 | this->in_sections_clause_ = false; | |
629 | } | |
630 | ||
631 | // Add a symbol to be defined. | |
632 | ||
633 | void | |
634 | Script_sections::add_symbol_assignment(const char* name, size_t length, | |
635 | Expression* val, bool provide, | |
636 | bool hidden) | |
637 | { | |
638 | if (this->output_section_ != NULL) | |
639 | this->output_section_->add_symbol_assignment(name, length, val, | |
640 | provide, hidden); | |
641 | else | |
642 | { | |
643 | Sections_element* p = new Sections_element_assignment(name, length, | |
644 | val, provide, | |
645 | hidden); | |
646 | this->sections_elements_->push_back(p); | |
647 | } | |
648 | } | |
649 | ||
650 | // Add an assertion. | |
651 | ||
652 | void | |
653 | Script_sections::add_assertion(Expression* check, const char* message, | |
654 | size_t messagelen) | |
655 | { | |
656 | if (this->output_section_ != NULL) | |
657 | this->output_section_->add_assertion(check, message, messagelen); | |
658 | else | |
659 | { | |
660 | Sections_element* p = new Sections_element_assertion(check, message, | |
661 | messagelen); | |
662 | this->sections_elements_->push_back(p); | |
663 | } | |
664 | } | |
665 | ||
666 | // Start processing entries for an output section. | |
667 | ||
668 | void | |
669 | Script_sections::start_output_section( | |
670 | const char* name, | |
671 | size_t namelen, | |
672 | const Parser_output_section_header *header) | |
673 | { | |
674 | Output_section_definition* posd = new Output_section_definition(name, | |
675 | namelen, | |
676 | header); | |
677 | this->sections_elements_->push_back(posd); | |
678 | gold_assert(this->output_section_ == NULL); | |
679 | this->output_section_ = posd; | |
680 | } | |
681 | ||
682 | // Stop processing entries for an output section. | |
683 | ||
684 | void | |
685 | Script_sections::finish_output_section( | |
686 | const Parser_output_section_trailer* trailer) | |
687 | { | |
688 | gold_assert(this->output_section_ != NULL); | |
689 | this->output_section_->finish(trailer); | |
690 | this->output_section_ = NULL; | |
691 | } | |
692 | ||
693 | // Add a data item to the current output section. | |
694 | ||
695 | void | |
696 | Script_sections::add_data(int size, bool is_signed, Expression* val) | |
697 | { | |
698 | gold_assert(this->output_section_ != NULL); | |
699 | this->output_section_->add_data(size, is_signed, val); | |
700 | } | |
701 | ||
702 | // Add a fill value setting to the current output section. | |
703 | ||
704 | void | |
705 | Script_sections::add_fill(Expression* val) | |
706 | { | |
707 | gold_assert(this->output_section_ != NULL); | |
708 | this->output_section_->add_fill(val); | |
709 | } | |
710 | ||
711 | // Add an input section specification to the current output section. | |
712 | ||
713 | void | |
714 | Script_sections::add_input_section(const Input_section_spec* spec, bool keep) | |
715 | { | |
716 | gold_assert(this->output_section_ != NULL); | |
717 | this->output_section_->add_input_section(spec, keep); | |
718 | } | |
719 | ||
720 | // Print the SECTIONS clause to F for debugging. | |
721 | ||
722 | void | |
723 | Script_sections::print(FILE* f) const | |
724 | { | |
725 | if (!this->saw_sections_clause_) | |
726 | return; | |
727 | ||
728 | fprintf(f, "SECTIONS {\n"); | |
729 | ||
730 | for (Sections_elements::const_iterator p = this->sections_elements_->begin(); | |
731 | p != this->sections_elements_->end(); | |
732 | ++p) | |
733 | (*p)->print(f); | |
734 | ||
735 | fprintf(f, "}\n"); | |
736 | } | |
737 | ||
738 | } // End namespace gold. |