root/trunk/ld/ld_layout.c @ 2628

Revision 2628, 19.9 KB (checked in by kaiwang27, 18 months ago)

Add support for OET_DATA_BUFFER elements layout.

  • Property svn:mime-type set to text/plain
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*-
2 * Copyright (c) 2011,2012 Kai Wang
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include "ld.h"
28#include "ld_arch.h"
29#include "ld_exp.h"
30#include "ld_file.h"
31#include "ld_script.h"
32#include "ld_input.h"
33#include "ld_output.h"
34#include "ld_layout.h"
35#include "ld_options.h"
36#include "ld_symbols.h"
37
38ELFTC_VCSID("$Id$");
39
40/*
41 * Support routines for output section layout.
42 */
43
44static void _calc_offset(struct ld *ld);
45static void _calc_output_section_offset(struct ld *ld,
46    struct ld_output_section *os);
47static void _insert_input_to_output(struct ld_output *lo,
48    struct ld_output_section *os, struct ld_input_section *is,
49    struct ld_input_section_head *islist);
50static void _layout_orphan_section(struct ld *ld, struct ld_input *li);
51static void _layout_output_section(struct ld *ld, struct ld_input *li,
52    struct ld_script_sections_output *ldso);
53static void _layout_sections(struct ld *ld, struct ld_script_sections *ldss);
54static void _parse_output_section_descriptor(struct ld *ld,
55    struct ld_output_section *os);
56static void _print_layout_map(struct ld *ld);
57static void _print_section_layout(struct ld *ld, struct ld_output_section *os);
58static void _print_wildcard(struct ld_wildcard *lw);
59static void _print_wildcard_list(struct ld_script_list *ldl);
60static void _set_output_section_loadable_flag(struct ld_output_section *os);
61static int _wildcard_match(struct ld_wildcard *lw, const char *string);
62static int _wildcard_list_match(struct ld_script_list *list,
63    const char *string);
64
65void
66ld_layout_sections(struct ld *ld)
67{
68        struct ld_output *lo;
69        struct ld_script *lds;
70        struct ld_script_cmd *ldc;
71        struct ld_state *ls;
72        int sections_cmd_exist;
73
74        ls = &ld->ld_state;
75        lo = ld->ld_output;
76        lds = ld->ld_scp;
77
78        sections_cmd_exist = 0;
79        STAILQ_FOREACH(ldc, &lds->lds_c, ldc_next) {
80                switch (ldc->ldc_type) {
81                case LSC_ASSERT:
82                        ld_output_create_element(ld, &lo->lo_oelist, OET_ASSERT,
83                            ldc->ldc_cmd, NULL);
84                        break;
85                case LSC_ASSIGN:
86                        ld_output_create_element(ld, &lo->lo_oelist, OET_ASSIGN,
87                            ldc->ldc_cmd, NULL);
88                        break;
89                case LSC_ENTRY:
90                        ld_output_create_element(ld, &lo->lo_oelist, OET_ENTRY,
91                            ldc->ldc_cmd, NULL);
92                        break;
93                case LSC_SECTIONS:
94                        if (sections_cmd_exist)
95                                ld_fatal(ld, "found multiple SECTIONS commands"
96                                    " in the linker script");
97                        sections_cmd_exist = 1;
98                        _layout_sections(ld, ldc->ldc_cmd);
99                        break;
100                default:
101                        break;
102                }
103        }
104        if (!sections_cmd_exist)
105                _layout_sections(ld, NULL);
106
107        /* Calculate section offsets of the output object. */
108        _calc_offset(ld);
109
110        /* Calculate symbol values and indices of the output object. */
111        ld_symbols_update(ld);
112
113        if (ld->ld_print_linkmap)
114                _print_layout_map(ld);
115}
116
117static void
118_print_layout_map(struct ld *ld)
119{
120        struct ld_input *li;
121        struct ld_input_section *is;
122        struct ld_output *lo;
123        struct ld_output_element *oe;
124        struct ld_script *lds;
125        int i;
126
127        lo = ld->ld_output;
128        assert(lo != NULL);
129
130        /* Print out the list of discarded sections. */
131        printf("\nDiscarded input sections:\n\n");
132        STAILQ_FOREACH(li, &ld->ld_lilist, li_next) {
133                for (i = 0; (size_t) i < li->li_shnum; i++) {
134                        is = &li->li_is[i];
135                        if (is->is_discard) {
136                                printf(" %-20s ", is->is_name);
137                                if (lo->lo_ec == ELFCLASS32)
138                                        printf("0x%08jx ",
139                                            (uintmax_t) is->is_addr);
140                                else
141                                        printf("0x%016jx ",
142                                            (uintmax_t) is->is_addr);
143                                printf("0x%jx ", (uintmax_t) is->is_size);
144                                printf("%s\n", ld_input_get_fullname(ld, li));
145                        }
146                }
147        }
148
149
150        lds = ld->ld_scp;
151        if (lds == NULL)
152                return;
153
154        /* TODO: Dump memory configuration */
155
156        printf("\nLinker script and memory map\n\n");
157
158        /* TODO: Dump loaded objects. */
159
160        STAILQ_FOREACH(oe, &lo->lo_oelist, oe_next) {
161
162                switch (oe->oe_type) {
163                case OET_ASSERT:
164                        /* TODO */
165                        break;
166                case OET_ASSIGN:
167                        ld_script_assign_dump(ld, oe->oe_entry);
168                        break;
169                case OET_ENTRY:
170                        /* TODO */
171                        break;
172                case OET_OUTPUT_SECTION:
173                        _print_section_layout(ld, oe->oe_entry);
174                        break;
175                default:
176                        break;
177                }
178        }
179}
180
181static void
182_print_section_layout(struct ld *ld, struct ld_output_section *os)
183{
184        struct ld_input_section *is;
185        struct ld_input_section_head *islist;
186        struct ld_output *lo;
187        struct ld_output_element *oe;
188        struct ld_script_sections_output_input *ldoi;
189
190        lo = ld->ld_output;
191
192        if (os->os_empty)
193                printf("\n%s\n", os->os_name);
194        else {
195                printf("\n%-15s", os->os_name);
196                if (lo->lo_ec == ELFCLASS32)
197                        printf(" 0x%08jx", (uintmax_t) os->os_addr);
198                else
199                        printf(" 0x%016jx", (uintmax_t) os->os_addr);
200                printf(" %#10jx\n", (uintmax_t) os->os_size);
201        }
202
203        STAILQ_FOREACH(oe, &os->os_e, oe_next) {
204                switch (oe->oe_type) {
205                case OET_ASSIGN:
206                        ld_script_assign_dump(ld, oe->oe_entry);
207                        break;
208                case OET_INPUT_SECTION_LIST:
209                        /*
210                         * Print out wildcard patterns and input sections
211                         * matched by these patterns.
212                         */
213                        ldoi = oe->oe_entry;
214                        if (ldoi == NULL)
215                                break;
216                        putchar(' ');
217                        if (ldoi->ldoi_ar) {
218                                _print_wildcard(ldoi->ldoi_ar);
219                                putchar(':');
220                        }
221                        _print_wildcard(ldoi->ldoi_file);
222                        putchar('(');
223                        if (ldoi->ldoi_exclude) {
224                                printf("(EXCLUDE_FILE(");
225                                _print_wildcard_list(ldoi->ldoi_exclude);
226                                putchar(')');
227                                putchar(' ');
228                        }
229                        _print_wildcard_list(ldoi->ldoi_sec);
230                        putchar(')');
231                        putchar('\n');
232                        if ((islist = oe->oe_islist) == NULL)
233                                break;
234                        STAILQ_FOREACH(is, islist, is_next) {
235                                if (!strcmp(is->is_name, "COMMON") &&
236                                    is->is_size == 0)
237                                        continue;
238                                printf(" %-14s", is->is_name);
239                                if (lo->lo_ec == ELFCLASS32)
240                                        printf(" 0x%08jx", (uintmax_t)
241                                            os->os_addr + is->is_reloff);
242                                else
243                                        printf(" 0x%016jx", (uintmax_t)
244                                            os->os_addr + is->is_reloff);
245                                if (is->is_size == 0)
246                                        printf(" %10s", "0x0");
247                                else
248                                        printf(" %#10jx", (uintmax_t)
249                                            is->is_size);
250                                printf(" %s\n", ld_input_get_fullname(ld,
251                                    is->is_input));
252                        }
253                        break;
254                default:
255                        break;
256                }
257        }
258}
259
260static void
261_print_wildcard(struct ld_wildcard *lw)
262{
263
264        switch (lw->lw_sort) {
265        case LWS_NONE:
266                printf("%s", lw->lw_name);
267                break;
268        case LWS_NAME:
269                printf("SORT_BY_NAME(%s)", lw->lw_name);
270                break;
271        case LWS_ALIGN:
272                printf("SORT_BY_ALIGNMENT(%s)", lw->lw_name);
273                break;
274        case LWS_NAME_ALIGN:
275                printf("SORT_BY_NAME(SORT_BY_ALIGNMENT(%s))", lw->lw_name);
276                break;
277        case LWS_ALIGN_NAME:
278                printf("SORT_BY_ALIGNMENT(SORT_BY_NAME(%s))", lw->lw_name);
279                break;
280        default:
281                break;
282        }
283}
284
285static void
286_print_wildcard_list(struct ld_script_list *ldl)
287{
288
289        _print_wildcard(ldl->ldl_entry);
290        if (ldl->ldl_next != NULL) {
291                putchar(' ');
292                _print_wildcard_list(ldl->ldl_next);
293        }
294}
295
296off_t
297ld_layout_calc_header_size(struct ld *ld)
298{
299        struct ld_script_phdr *ldsp;
300        struct ld_output *lo;
301        struct ld_output_section *os;
302        off_t header_size;
303        unsigned ec, w, num_phdrs;
304        int new;
305
306        lo = ld->ld_output;
307        assert(lo != NULL);
308
309        header_size = 0;
310
311        ec = elftc_bfd_target_class(ld->ld_otgt);
312
313        if (ec == ELFCLASS32)
314                header_size += sizeof(Elf32_Ehdr);
315        else
316                header_size += sizeof(Elf64_Ehdr);
317
318        if (!STAILQ_EMPTY(&ld->ld_scp->lds_p)) {
319                num_phdrs = 0;
320                STAILQ_FOREACH(ldsp, &ld->ld_scp->lds_p, ldsp_next)
321                        num_phdrs++;
322        } else {
323                if (lo->lo_phdr_num > 0)
324                        num_phdrs = lo->lo_phdr_num;
325                else {
326                        num_phdrs = 0;
327                        new = 1;
328                        w = 0;
329                        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
330                                if (os->os_empty)
331                                        continue;
332
333                                if ((os->os_flags & SHF_ALLOC) == 0) {
334                                        new = 1;
335                                        continue;
336                                }
337
338                                if ((os->os_flags & SHF_WRITE) != w || new) {
339                                        new = 0;
340                                        num_phdrs++;
341                                        w = os->os_flags & SHF_WRITE;
342                                }
343                        }
344
345                        if (lo->lo_phdr_note)
346                                num_phdrs++;
347
348                        if (ld->ld_gen_gnustack)
349                                num_phdrs++;
350
351                        if (lo->lo_phdr_num != 0 &&
352                            lo->lo_phdr_num != num_phdrs)
353                                ld_fatal(ld, "not enough room for program"
354                                    " headers");
355                }
356        }
357
358        if (ec == ELFCLASS32)
359                header_size += num_phdrs * sizeof(Elf32_Phdr);
360        else
361                header_size += num_phdrs * sizeof(Elf64_Phdr);
362
363        lo->lo_phdr_num = num_phdrs;
364
365        return (header_size);
366}
367
368static void
369_layout_sections(struct ld *ld, struct ld_script_sections *ldss)
370{
371        struct ld_input *li;
372        struct ld_output *lo;
373        struct ld_script_cmd *ldc;
374        int first;
375
376        ld_input_link_objects(ld);
377
378        first = 1;
379        lo = ld->ld_output;
380        STAILQ_FOREACH(li, &ld->ld_lilist, li_next) {
381                ld_input_init_sections(ld, li);
382                if (li->li_type != LIT_RELOCATABLE)
383                        continue;
384                STAILQ_FOREACH(ldc, &ldss->ldss_c, ldc_next) {
385                        switch (ldc->ldc_type) {
386                        case LSC_ASSERT:
387                                if (!first)
388                                        break;
389                                ld_output_create_element(ld, &lo->lo_oelist,
390                                    OET_ASSIGN, ldc->ldc_cmd, NULL);
391                        case LSC_ASSIGN:
392                                if (!first)
393                                        break;
394                                ld_output_create_element(ld, &lo->lo_oelist,
395                                    OET_ASSIGN, ldc->ldc_cmd, NULL);
396                                break;
397                        case LSC_ENTRY:
398                                ld_output_create_element(ld, &lo->lo_oelist,
399                                    OET_ENTRY, ldc->ldc_cmd, NULL);
400                                break;
401                        case LSC_SECTIONS_OUTPUT:
402                                _layout_output_section(ld, li, ldc->ldc_cmd);
403                                break;
404                        case LSC_SECTIONS_OVERLAY:
405                                /* TODO */
406                                break;
407                        default:
408                                break;
409                        }
410                }
411                first = 0;
412        }
413
414        STAILQ_FOREACH(li, &ld->ld_lilist, li_next) {
415                if (li->li_type != LIT_RELOCATABLE)
416                        continue;
417                _layout_orphan_section(ld, li);
418        }
419
420        /* Create PLT and GOT sections if need. */
421        if (HASH_COUNT(ld->ld_symtab_import) > 0)
422                ld->ld_arch->create_pltgot(ld);
423}
424
425static int
426_wildcard_match(struct ld_wildcard *lw, const char *string)
427{
428
429        return (fnmatch(lw->lw_name, string, 0) == 0);
430}
431
432static int
433_wildcard_list_match(struct ld_script_list *list, const char *string)
434{
435        struct ld_script_list *ldl;
436
437        for (ldl = list; ldl != NULL; ldl = ldl->ldl_next)
438                if (_wildcard_match(ldl->ldl_entry, string))
439                        return (1);
440
441        return (0);
442}
443
444static void
445_set_output_section_loadable_flag(struct ld_output_section *os)
446{
447        struct ld_script_sections_output *ldso;
448        struct ld_exp *le;
449
450        if ((ldso = os->os_ldso) == NULL)
451                return;
452
453        if (ldso->ldso_vma == NULL)
454                os->os_flags |= SHF_ALLOC;
455        else {
456                le = ldso->ldso_vma;
457                if (le->le_op != LEOP_CONSTANT || le->le_val != 0)
458                        os->os_flags |= SHF_ALLOC;
459        }
460
461        if (ldso->ldso_type != NULL && strcmp(ldso->ldso_type, "NOLOAD") == 0)
462                os->os_flags &= ~SHF_ALLOC;
463}
464
465static void
466_layout_output_section(struct ld *ld, struct ld_input *li,
467    struct ld_script_sections_output *ldso)
468{
469        struct ld_file *lf;
470        struct ld_output *lo;
471        struct ld_script_cmd *ldc;
472        struct ld_script_sections_output_input *ldoi;
473        struct ld_input_section *is;
474        struct ld_input_section_head *islist;
475        struct ld_output_element *oe;
476        struct ld_output_section *os;
477        int i, new_section;
478
479        lf = li->li_file;
480        lo = ld->ld_output;
481        new_section = 0;
482        oe = NULL;
483        HASH_FIND_STR(lo->lo_ostbl, ldso->ldso_name, os);
484        if (os == NULL) {
485                os = ld_output_alloc_section(ld, ldso->ldso_name, NULL);
486                os->os_ldso = ldso;
487                _set_output_section_loadable_flag(os);
488                new_section = 1;
489        } else
490                oe = STAILQ_FIRST(&os->os_e);
491
492        STAILQ_FOREACH(ldc, &ldso->ldso_c, ldc_next) {
493                switch (ldc->ldc_type) {
494                case LSC_ASSERT:
495                        if (new_section)
496                                oe = ld_output_create_element(ld, &os->os_e,
497                                    OET_ASSERT, ldc->ldc_cmd, NULL);
498                        break;
499                case LSC_ASSIGN:
500                        if (new_section)
501                                oe = ld_output_create_element(ld, &os->os_e,
502                                    OET_ASSIGN, ldc->ldc_cmd, NULL);
503                        break;
504                case LSC_SECTIONS_OUTPUT_DATA:
505                        if (new_section)
506                                oe = ld_output_create_element(ld, &os->os_e,
507                                    OET_DATA, ldc->ldc_cmd, NULL);
508                        break;
509                case LSC_SECTIONS_OUTPUT_INPUT:
510                        if (new_section) {
511                                islist = calloc(1, sizeof(*islist));
512                                if (islist == NULL)
513                                        ld_fatal_std(ld, "calloc");
514                                STAILQ_INIT(islist);
515                                oe = ld_output_create_element(ld, &os->os_e,
516                                    OET_INPUT_SECTION_LIST, ldc->ldc_cmd, NULL);
517                                oe->oe_islist = islist;
518                        }
519                        break;
520                case LSC_SECTIONS_OUTPUT_KEYWORD:
521                        if (new_section)
522                                ld_output_create_element(ld, &os->os_e,
523                                    OET_KEYWORD, ldc->ldc_cmd, NULL);
524                        break;
525                default:
526                        ld_fatal(ld, "internal: invalid output section "
527                            "command: %d", ldc->ldc_type);
528                }
529                if (ldc->ldc_type != LSC_SECTIONS_OUTPUT_INPUT)
530                        goto next_output_cmd;
531
532                ldoi = ldc->ldc_cmd;
533
534                if (ldoi->ldoi_ar != NULL && li->li_lam != NULL &&
535                    !_wildcard_match(ldoi->ldoi_ar, lf->lf_name))
536                        goto next_output_cmd;
537
538                assert(ldoi->ldoi_file != NULL);
539                if (!_wildcard_match(ldoi->ldoi_file, li->li_name))
540                        goto next_output_cmd;
541
542                if (ldoi->ldoi_exclude != NULL &&
543                    _wildcard_list_match(ldoi->ldoi_exclude, li->li_name))
544                        goto next_output_cmd;
545
546                assert(ldoi->ldoi_sec != NULL);
547                for (i = 1; (size_t) i < li->li_shnum; i++) {
548                        is = &li->li_is[i];
549                        if (!is->is_orphan)
550                                continue;
551                        if (!_wildcard_list_match(ldoi->ldoi_sec, is->is_name))
552                                continue;
553                        if (strcmp(os->os_name, "/DISCARD/") == 0) {
554                                is->is_discard = 1;
555                                continue;
556                        }
557                        assert(oe != NULL &&
558                            oe->oe_type == OET_INPUT_SECTION_LIST);
559                        _insert_input_to_output(lo, os, is, oe->oe_islist);
560                }
561
562        next_output_cmd:
563                assert(oe != NULL);
564                if (!new_section)
565                        oe = STAILQ_NEXT(oe, oe_next);                 
566        }
567}
568
569static void
570_layout_orphan_section(struct ld *ld, struct ld_input *li)
571{
572        struct ld_input_section *is;
573        struct ld_input_section_head *islist;
574        struct ld_output *lo;
575        struct ld_output_element *oe;
576        struct ld_output_section *os, *_os;
577        int i;
578
579        /*
580         * Layout the input sections that are not listed in the output
581         * section descriptor in the linker script.
582         */
583
584        lo = ld->ld_output;
585        for (i = 1; (size_t) i < li->li_shnum; i++) {
586                is = &li->li_is[i];
587
588                if (!is->is_orphan || is->is_discard)
589                        continue;
590
591                if (strcmp(is->is_name, ".shstrtab") == 0 ||
592                    strcmp(is->is_name, ".symtab") == 0 ||
593                    strcmp(is->is_name, ".strtab") == 0)
594                        continue;
595
596                if ((is->is_type == SHT_REL || is->is_type == SHT_RELA) &&
597                    !ld->ld_emit_reloc)
598                        continue;
599
600                HASH_FIND_STR(lo->lo_ostbl, is->is_name, os);
601                if (os != NULL) {
602                        oe = STAILQ_FIRST(&os->os_e);
603                        assert(oe != NULL &&
604                            oe->oe_type == OET_INPUT_SECTION_LIST);
605                        _insert_input_to_output(lo, os, is, oe->oe_islist);
606                        continue;
607                }
608
609                /*
610                 * Create a new output secton and put it in a proper place,
611                 * based on the section flag.
612                 */
613                _os = ld_layout_insert_output_section(ld, is->is_name,
614                    is->is_flags);
615
616                if ((islist = calloc(1, sizeof(*islist))) == NULL)
617                        ld_fatal_std(ld, "calloc");
618                STAILQ_INIT(islist);
619
620                oe = ld_output_create_element(ld, &_os->os_e,
621                    OET_INPUT_SECTION_LIST, NULL, NULL);
622                oe->oe_islist = islist;
623                _insert_input_to_output(lo, _os, is, oe->oe_islist);
624        }
625}
626
627struct ld_output_section *
628ld_layout_insert_output_section(struct ld *ld, const char *name,
629    uint64_t flags)
630{
631        struct ld_output *lo;
632        struct ld_output_section *os, *_os;
633
634        lo = ld->ld_output;
635        assert(lo != NULL);
636
637        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
638                if ((os->os_flags & SHF_ALLOC) != (flags & SHF_ALLOC))
639                        continue;
640
641                if (os->os_flags == flags) {
642                        _os = STAILQ_NEXT(os, os_next);
643                        if (_os == NULL || _os->os_flags != flags)
644                                break;
645                }
646
647                _os = STAILQ_NEXT(os, os_next);
648                if (_os == NULL &&
649                    (_os->os_flags & SHF_ALLOC) != (flags & SHF_ALLOC))
650                        break;
651        }
652
653        _os = ld_output_alloc_section(ld, name, os);
654        _os->os_flags |= flags & SHF_ALLOC;
655
656        return (_os);
657}
658
659static void
660_insert_input_to_output(struct ld_output *lo, struct ld_output_section *os,
661    struct ld_input_section *is, struct ld_input_section_head *islist)
662{
663
664        /*
665         * TODO: Since we now only support "-static" linking, assume all
666         * input relocation sections has been processed and consumed.
667         */
668        if (is->is_type == SHT_REL || is->is_type == SHT_RELA)
669                return;
670
671        is->is_orphan = 0;
672        os->os_empty = 0;
673
674        os->os_flags |= is->is_flags & (SHF_EXECINSTR | SHF_WRITE);
675
676        if (is->is_align > os->os_align)
677                os->os_align = is->is_align;
678
679        if (os->os_type == SHT_NULL)
680                os->os_type = is->is_type;
681        if (is->is_type == SHT_NOTE)
682                lo->lo_phdr_note = 1;
683
684        is->is_output = os;
685        STAILQ_INSERT_TAIL(islist, is, is_next);
686}
687
688static void
689_parse_output_section_descriptor(struct ld *ld, struct ld_output_section *os)
690{
691        struct ld_script_sections_output *ldso;
692
693        if ((ldso = os->os_ldso) == NULL)
694                return;
695
696        if (ldso->ldso_vma != NULL)
697                os->os_addr = ld_exp_eval(ld, ldso->ldso_vma);
698
699        if (ldso->ldso_lma != NULL)
700                os->os_lma = ld_exp_eval(ld, ldso->ldso_lma);
701
702        if (ldso->ldso_align != NULL)
703                os->os_align = ld_exp_eval(ld, ldso->ldso_align);
704
705        /* TODO: handle other output section parameters. */
706}
707
708static void
709_calc_offset(struct ld *ld)
710{
711        struct ld_state *ls;
712        struct ld_output *lo;
713        struct ld_output_element *oe;
714
715        ls = &ld->ld_state;
716        lo = ld->ld_output;
717        ls->ls_loc_counter = 0;
718        ls->ls_offset = ld_layout_calc_header_size(ld);
719
720        STAILQ_FOREACH(oe, &lo->lo_oelist, oe_next) {
721                switch (oe->oe_type) {
722                case OET_ASSERT:
723                        /* TODO */
724                        break;
725                case OET_ASSIGN:
726                        ld_script_process_assign(ld, oe->oe_entry);
727                        break;
728                case OET_ENTRY:
729                        ld_script_process_entry(ld, oe->oe_entry);
730                        break;
731                case OET_OUTPUT_SECTION:
732                        _parse_output_section_descriptor(ld, oe->oe_entry);
733                        _calc_output_section_offset(ld, oe->oe_entry);
734                        break;
735                default:
736                        break;
737                }
738        }
739}
740
741static void
742_calc_output_section_offset(struct ld *ld, struct ld_output_section *os)
743{
744        struct ld_state *ls;
745        struct ld_output_element *oe;
746        struct ld_output_data_buffer *odb;
747        struct ld_input_section *is;
748        struct ld_input_section_head *islist;
749        uint64_t addr;
750
751        ls = &ld->ld_state;
752
753        /*
754         * Location counter is an offset relative to the start of the
755         * section, when it's refered inside an output section descriptor.
756         */
757        addr = ls->ls_loc_counter;
758        ls->ls_loc_counter = 0;
759
760        STAILQ_FOREACH(oe, &os->os_e, oe_next) {
761                switch (oe->oe_type) {
762                case OET_ASSERT:
763                        /* TODO */
764                        break;
765                case OET_ASSIGN:
766                        ld_script_process_assign(ld, oe->oe_entry);
767                        break;
768                case OET_DATA:
769                        /* TODO */
770                        break;
771                case OET_DATA_BUFFER:
772                        odb = oe->oe_entry;
773                        odb->odb_off = roundup(ls->ls_loc_counter,
774                            odb->odb_align);
775                        ls->ls_loc_counter = odb->odb_off + odb->odb_size;
776                        break;
777                case OET_ENTRY:
778                        ld_script_process_entry(ld, oe->oe_entry);
779                        break;
780                case OET_INPUT_SECTION_LIST:
781                        islist = oe->oe_islist;
782                        STAILQ_FOREACH(is, islist, is_next) {
783                                if (is->is_size == 0)
784                                        continue;
785                                is->is_reloff = roundup(ls->ls_loc_counter,
786                                    is->is_align);
787#if 0
788                                printf("\t%s(%s): %#jx,%#jx(%#jx)\n",
789                                    is->is_input->li_name,
790                                    is->is_name, is->is_reloff,
791                                    is->is_size, is->is_align);
792#endif
793                                ls->ls_loc_counter = is->is_reloff +
794                                    is->is_size;
795                        }
796                        break;
797                case OET_KEYWORD:
798                        /* TODO */
799                        break;
800                default:
801                        break;
802                }
803        }
804
805        /*
806         * Properly align section vma and offset to the required section
807         * alignment.
808         */
809
810        if (os->os_flags & SHF_ALLOC) {
811                if (os->os_ldso == NULL || os->os_ldso->ldso_vma == NULL)
812                        os->os_addr = roundup(addr, os->os_align);
813        } else
814                os->os_addr = 0;
815
816        os->os_off = roundup(ls->ls_offset, os->os_align);
817        os->os_size = ls->ls_loc_counter;
818
819#if 0
820        printf("layout output section %s: (off:%#jx,size:%#jx) "
821            "vma:%#jx,align:%#jx\n", os->os_name, os->os_off, os->os_size,
822            os->os_addr, os->os_align);
823#endif
824
825        ls->ls_offset = os->os_off + os->os_size;
826
827        /* Reset location counter to the current VMA. */
828        if (os->os_flags & SHF_ALLOC)
829                ls->ls_loc_counter = os->os_addr + os->os_size;
830}
Note: See TracBrowser for help on using the browser.