root/trunk/ld/ld_output.c @ 2685

Revision 2685, 21.6 KB (checked in by kaiwang27, 17 months ago)

Generate PT_DYNAMIC entry for dynamically linked output object.

  • 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_input.h"
30#include "ld_output.h"
31#include "ld_layout.h"
32#include "ld_reloc.h"
33#include "ld_script.h"
34#include "ld_strtab.h"
35#include "ld_symbols.h"
36
37ELFTC_VCSID("$Id$");
38
39static void _alloc_input_section_data(struct ld *ld, Elf_Scn *scn,
40    struct ld_input_section *is);
41static void _alloc_section_data_from_buffer(struct ld *ld, Elf_Scn *scn,
42    struct ld_output_data_buffer *odb);
43static void _alloc_section_data_for_symtab(struct ld *ld,
44    struct ld_output_section *os, Elf_Scn *scn,
45    struct ld_symbol_table *symtab);
46static void _alloc_section_data_for_strtab(struct ld *ld, Elf_Scn *scn,
47    struct ld_strtab *strtab);
48static void _add_to_shstrtab(struct ld *ld, const char *name);
49static void _copy_and_reloc_input_sections(struct ld *ld);
50static Elf_Scn *_create_elf_scn(struct ld *ld, struct ld_output *lo,
51    struct ld_output_section *os);
52static void _create_elf_section(struct ld *ld, struct ld_output_section *os);
53static void _create_elf_sections(struct ld *ld);
54static void _create_phdr(struct ld *ld);
55static void _create_string_table_section(struct ld *ld, const char *name,
56    struct ld_strtab *st, Elf_Scn *scn);
57static void _create_symbol_table(struct ld *ld);
58static uint64_t _find_entry_point(struct ld *ld);
59static uint64_t _insert_shdr(struct ld *ld);
60static void _update_section_header(struct ld *ld);
61
62void
63ld_output_init(struct ld *ld)
64{
65        struct ld_output *lo;
66
67        if ((lo = calloc(1, sizeof(*lo))) == NULL)
68                ld_fatal_std(ld, "calloc");
69
70        STAILQ_INIT(&lo->lo_oelist);
71        STAILQ_INIT(&lo->lo_oslist);
72        ld->ld_output = lo;
73}
74
75void
76ld_output_format(struct ld *ld, char *def, char *be, char *le)
77{
78
79        ld->ld_otgt_name = def;
80        if ((ld->ld_otgt = elftc_bfd_find_target(def)) == NULL)
81                ld_fatal(ld, "invalid BFD format %s", def);
82
83        ld->ld_otgt_be_name = be;
84        if ((ld->ld_otgt_be = elftc_bfd_find_target(be)) == NULL)
85                ld_fatal(ld, "invalid BFD format %s", be);
86
87        ld->ld_otgt_le_name = le;
88        if ((ld->ld_otgt_le = elftc_bfd_find_target(le)) == NULL)
89                ld_fatal(ld, "invalid BFD format %s", le);
90
91        ld_arch_set_from_target(ld);
92}
93
94struct ld_output_element *
95ld_output_create_element(struct ld *ld, struct ld_output_element_head *head,
96    enum ld_output_element_type type, void *entry,
97    struct ld_output_element *after)
98{
99        struct ld_output_element *oe;
100
101        if ((oe = calloc(1, sizeof(*oe))) == NULL)
102                ld_fatal_std(ld, "calloc");
103
104        oe->oe_type = type;
105        oe->oe_entry = entry;
106
107        if (after == NULL)
108                STAILQ_INSERT_TAIL(head, oe, oe_next);
109        else
110                STAILQ_INSERT_AFTER(head, after, oe, oe_next);
111
112        return (oe);
113}
114
115struct ld_output_section *
116ld_output_alloc_section(struct ld *ld, const char *name,
117    struct ld_output_section *after)
118{
119        struct ld_output *lo;
120        struct ld_output_section *os;
121
122        lo = ld->ld_output;
123
124        if ((os = calloc(1, sizeof(*os))) == NULL)
125                ld_fatal_std(ld, "calloc");
126
127        if ((os->os_name = strdup(name)) == NULL)
128                ld_fatal_std(ld, "strdup");
129
130        os->os_align = 1;
131        os->os_empty = 1;
132
133        STAILQ_INIT(&os->os_e);
134
135        HASH_ADD_KEYPTR(hh, lo->lo_ostbl, os->os_name, strlen(os->os_name), os);
136
137        if (after == NULL) {
138                STAILQ_INSERT_TAIL(&lo->lo_oslist, os, os_next);
139                os->os_pe = ld_output_create_element(ld, &lo->lo_oelist,
140                    OET_OUTPUT_SECTION, os, NULL);
141        } else {
142                STAILQ_INSERT_AFTER(&lo->lo_oslist, after, os, os_next);
143                os->os_pe = ld_output_create_element(ld, &lo->lo_oelist,
144                    OET_OUTPUT_SECTION, os, after->os_pe);
145        }
146
147        return (os);
148}
149
150static Elf_Scn *
151_create_elf_scn(struct ld *ld, struct ld_output *lo,
152    struct ld_output_section *os)
153{
154        Elf_Scn *scn;
155
156        assert(lo->lo_elf != NULL);
157
158        if ((scn = elf_newscn(lo->lo_elf)) == NULL)
159                ld_fatal(ld, "elf_newscn failed: %s", elf_errmsg(-1));
160
161        if (os != NULL)
162                os->os_scn = scn;
163
164        return (scn);
165}
166
167static void
168_create_elf_section(struct ld *ld, struct ld_output_section *os)
169{
170        struct ld_output *lo;
171        struct ld_output_element *oe;
172        struct ld_input_section *is;
173        struct ld_input_section_head *islist;
174        Elf_Data *d;
175        Elf_Scn *scn;
176        GElf_Shdr sh;
177
178        lo = ld->ld_output;
179        assert(lo->lo_elf != NULL);
180
181        /* Create section data. */
182        scn = NULL;
183        STAILQ_FOREACH(oe, &os->os_e, oe_next) {
184                switch (oe->oe_type) {
185                case OET_DATA:
186                        if (scn == NULL)
187                                scn = _create_elf_scn(ld, lo, os);
188                        /* TODO */
189                        break;
190                case OET_DATA_BUFFER:
191                        if (scn == NULL)
192                                scn = _create_elf_scn(ld, lo, os);
193                        _alloc_section_data_from_buffer(ld, scn, oe->oe_entry);
194                        break;
195                case OET_INPUT_SECTION_LIST:
196                        islist = oe->oe_islist;
197                        STAILQ_FOREACH(is, islist, is_next) {
198                                if (scn == NULL)
199                                        scn = _create_elf_scn(ld, lo, os);
200                                if (os->os_type != SHT_NOBITS)
201                                        _alloc_input_section_data(ld, scn, is);
202                        }
203                        break;
204                case OET_KEYWORD:
205                        if (scn == NULL)
206                                scn = _create_elf_scn(ld, lo, os);
207                        /* TODO */
208                        break;
209                case OET_SYMTAB:
210                        /* TODO: Check symtab size. */
211                        if (scn == NULL)
212                                scn = _create_elf_scn(ld, lo, os);
213                        break;
214                case OET_STRTAB:
215                        /* TODO: Check strtab size. */
216                        if (scn == NULL)
217                                scn = _create_elf_scn(ld, lo, os);
218                        _alloc_section_data_for_strtab(ld, scn, oe->oe_entry);
219                        break;
220                default:
221                        break;
222                }
223        }
224
225        if (scn == NULL)
226                return;
227
228        if (os->os_type == SHT_NOBITS) {
229                if ((d = elf_newdata(scn)) == NULL)
230                        ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
231
232                d->d_align = os->os_align;
233                d->d_off = 0;
234                d->d_type = ELF_T_BYTE;
235                d->d_size = os->os_size;
236                d->d_version = EV_CURRENT;
237                d->d_buf = NULL;
238        }
239
240        if (gelf_getshdr(scn, &sh) == NULL)
241                ld_fatal(ld, "gelf_getshdr failed: %s", elf_errmsg(-1));
242
243        sh.sh_flags = os->os_flags;
244        sh.sh_addr = os->os_addr;
245        sh.sh_addralign = os->os_align;
246        sh.sh_offset = os->os_off;
247        sh.sh_size = os->os_size;
248        sh.sh_type = os->os_type;
249        sh.sh_entsize = os->os_entsize;
250
251        _add_to_shstrtab(ld, os->os_name);
252
253        if (!gelf_update_shdr(scn, &sh))
254                ld_fatal(ld, "gelf_update_shdr failed: %s", elf_errmsg(-1));
255}
256
257static void
258_alloc_input_section_data(struct ld *ld, Elf_Scn *scn,
259    struct ld_input_section *is)
260{
261        Elf_Data *d;
262
263        if (is->is_type == SHT_NOBITS || is->is_size == 0)
264                return;
265
266        if ((d = elf_newdata(scn)) == NULL)
267                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
268
269        is->is_data = d;
270}
271
272static void
273_alloc_section_data_from_buffer(struct ld *ld, Elf_Scn *scn,
274    struct ld_output_data_buffer *odb)
275{
276        Elf_Data *d;
277
278        if ((d = elf_newdata(scn)) == NULL)
279                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
280
281        d->d_align = odb->odb_align;
282        d->d_off = odb->odb_off;
283        d->d_type = odb->odb_type;
284        d->d_size = odb->odb_size;
285        d->d_version = EV_CURRENT;
286        d->d_buf = odb->odb_buf;
287}
288
289static void
290_alloc_section_data_for_symtab(struct ld *ld, struct ld_output_section *os,
291    Elf_Scn *scn, struct ld_symbol_table *symtab)
292{
293        Elf_Data *d;
294
295        if (symtab->sy_buf == NULL || symtab->sy_size == 0)
296                return;
297
298        if ((d = elf_newdata(scn)) == NULL)
299                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
300
301        d->d_align = os->os_align;
302        d->d_off = 0;
303        d->d_type = ELF_T_SYM;
304        d->d_size = os->os_entsize * symtab->sy_size;
305        d->d_version = EV_CURRENT;
306        d->d_buf = symtab->sy_buf;
307}
308
309static void
310_alloc_section_data_for_strtab(struct ld *ld, Elf_Scn *scn,
311    struct ld_strtab *strtab)
312{
313        Elf_Data *d;
314
315        if (strtab->st_buf == NULL || strtab->st_size == 0)
316                return;
317
318        if ((d = elf_newdata(scn)) == NULL)
319                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
320
321        d->d_align = 1;
322        d->d_off = 0;
323        d->d_type = ELF_T_BYTE;
324        d->d_size = strtab->st_size;
325        d->d_version = EV_CURRENT;
326        d->d_buf = strtab->st_buf;
327}
328
329static void
330_copy_and_reloc_input_sections(struct ld *ld)
331{
332        struct ld_input *li;
333        struct ld_input_section *is;
334        Elf_Data *d;
335        int i;
336
337        STAILQ_FOREACH(li, &ld->ld_lilist, li_next) {
338                ld_input_load(ld, li);
339                for (i = 0; (uint64_t) i < li->li_shnum; i++) {
340                        is = &li->li_is[i];
341                        if (is->is_data == NULL)
342                                continue;
343                        d = is->is_data;
344                        d->d_align = is->is_align;
345                        d->d_off = is->is_reloff;
346                        d->d_type = ELF_T_BYTE;
347                        d->d_size = is->is_size;
348                        d->d_version = EV_CURRENT;
349                        d->d_buf = ld_input_get_section_rawdata(ld, is);
350                        ld_reloc_process_input_section(ld, is, d->d_buf);
351                }
352                ld_input_unload(ld, li);
353        }
354}
355
356static void
357_create_elf_sections(struct ld *ld)
358{
359        struct ld_output *lo;
360        struct ld_output_element *oe;
361
362        lo = ld->ld_output;
363        assert(lo->lo_elf != NULL);
364
365        STAILQ_FOREACH(oe, &lo->lo_oelist, oe_next) {
366                switch (oe->oe_type) {
367                case OET_OUTPUT_SECTION:
368                        _create_elf_section(ld, oe->oe_entry);
369                        break;
370                default:
371                        break;
372                }
373        }
374}
375
376static uint64_t
377_find_entry_point(struct ld *ld)
378{
379        struct ld_output *lo;
380        struct ld_output_section *os;
381        char entry_symbol[] = "start";
382        uint64_t entry;
383
384        lo = ld->ld_output;
385
386        if (ld->ld_entry != NULL) {
387                if (ld_symbols_get_value(ld, ld->ld_entry, &entry) < 0)
388                        ld_fatal(ld, "symbol %s is undefined", ld->ld_entry);
389                return (entry);
390        }
391
392        if (ld->ld_scp->lds_entry_point != NULL) {
393                if (ld_symbols_get_value(ld, ld->ld_scp->lds_entry_point,
394                    &entry) == 0)
395                        return (entry);
396        }
397
398        if (ld_symbols_get_value(ld, entry_symbol, &entry) == 0)
399                return (entry);
400
401        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
402                if (os->os_empty)
403                        continue;
404                if (strcmp(os->os_name, ".text") == 0)
405                        return (os->os_addr);
406        }
407
408        return (0);
409}
410
411static void
412_create_phdr(struct ld *ld)
413{
414        struct ld_output *lo;
415        struct ld_output_section *os;
416        Elf32_Phdr *p32;
417        Elf64_Phdr *p64;
418        void *phdrs;
419        uint64_t addr, off, align, flags, filesz, memsz, phdr_addr;
420        unsigned w;
421        int i, new, first;
422
423        /* TODO: support segments created by linker script command PHDR. */
424
425#define _WRITE_PHDR(T,O,A,FSZ,MSZ,FL,AL)                \
426        do {                                            \
427                if (lo->lo_ec == ELFCLASS32) {          \
428                        p32[i].p_type = (T);            \
429                        p32[i].p_offset = (O);          \
430                        p32[i].p_vaddr = (A);           \
431                        p32[i].p_paddr = (A);           \
432                        p32[i].p_filesz = (FSZ);        \
433                        p32[i].p_memsz = (MSZ);         \
434                        p32[i].p_flags = (FL);          \
435                        p32[i].p_align = (AL);          \
436                } else {                                \
437                        p64[i].p_type = (T);            \
438                        p64[i].p_offset = (O);          \
439                        p64[i].p_vaddr = (A);           \
440                        p64[i].p_paddr = (A);           \
441                        p64[i].p_filesz = (FSZ);        \
442                        p64[i].p_memsz = (MSZ);         \
443                        p64[i].p_flags = (FL);          \
444                        p64[i].p_align = (AL);          \
445                }                                       \
446        } while(0)
447
448        lo = ld->ld_output;
449        assert(lo->lo_elf != NULL);
450        assert(lo->lo_phdr_num != 0);
451        assert(ld->ld_arch != NULL);
452
453        if ((phdrs = gelf_newphdr(lo->lo_elf, lo->lo_phdr_num)) == NULL)
454                ld_fatal(ld, "gelf_newphdr failed: %s", elf_errmsg(-1));
455
456        p32 = NULL;
457        p64 = NULL;
458        if (lo->lo_ec == ELFCLASS32)
459                p32 = phdrs;
460        else
461                p64 = phdrs;
462
463        i = -1;
464
465        /* Calculate the start vma of output object. */
466        os = STAILQ_FIRST(&lo->lo_oslist);
467        addr = os->os_addr - os->os_off;
468
469        /* Create PT_PHDR segment for dynamically linked output object */
470        if (lo->lo_dso_needed > 0) {
471                i++;
472                off = gelf_fsize(lo->lo_elf, ELF_T_EHDR, 1, EV_CURRENT);
473                phdr_addr = addr + off;
474                filesz = memsz = gelf_fsize(lo->lo_elf, ELF_T_PHDR,
475                    lo->lo_phdr_num, EV_CURRENT);
476                align = lo->lo_ec == ELFCLASS32 ? 4 : 8;
477                flags = PF_R | PF_X;
478                _WRITE_PHDR(PT_PHDR, off, phdr_addr, filesz, memsz, flags,
479                    align);
480        }
481
482        /* Create PT_INTERP segment for dynamically linked output object */
483        if (lo->lo_interp != NULL) {
484                i++;
485                os = lo->lo_interp;
486                _WRITE_PHDR(PT_INTERP, os->os_off, os->os_addr, os->os_size,
487                    os->os_size, PF_R, 1);
488        }
489
490        /*
491         * Create PT_LOAD segments.
492         */
493
494        align = ld->ld_arch->get_max_page_size(ld);
495        new = 1;
496        w = 0;
497        filesz = 0;
498        memsz = 0;
499        flags = PF_R;
500        off = 0;
501        first = 1;
502
503        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
504                if (os->os_empty)
505                        continue;
506
507                if ((os->os_flags & SHF_ALLOC) == 0) {
508                        new = 1;
509                        continue;
510                }
511
512                if ((os->os_flags & SHF_WRITE) != w || new) {
513                        new = 0;
514                        w = os->os_flags & SHF_WRITE;
515
516                        if (!first)
517                                _WRITE_PHDR(PT_LOAD, off, addr, filesz, memsz,
518                                    flags, align);
519
520                        i++;
521                        if ((unsigned) i >= lo->lo_phdr_num)
522                                ld_fatal(ld, "not enough room for program"
523                                    " headers");
524                        if (!first) {
525                                addr = os->os_addr;
526                                off = os->os_off;
527                        }
528                        first = 0;
529                        flags = PF_R;
530                        filesz = 0;
531                        memsz = 0;
532                }
533
534                memsz = os->os_addr + os->os_size - addr;
535                if (os->os_type != SHT_NOBITS)
536                        filesz = memsz;
537
538                if (os->os_flags & SHF_WRITE)
539                        flags |= PF_W;
540
541                if (os->os_flags & SHF_EXECINSTR)
542                        flags |= PF_X;
543        }
544        if (i >= 0)
545                _WRITE_PHDR(PT_LOAD, off, addr, filesz, memsz, flags, align);
546
547        /*
548         * Create PT_DYNAMIC segment.
549         */
550        if (lo->lo_dynamic != NULL) {
551                i++;
552                os = lo->lo_dynamic;
553                _WRITE_PHDR(PT_DYNAMIC, os->os_off, os->os_addr, os->os_size,
554                    os->os_size, PF_R | PF_W, lo->lo_ec == ELFCLASS32 ? 4 : 8);
555        }
556
557        /*
558         * Create PT_NOTE segment.
559         */
560
561        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
562                if (os->os_type == SHT_NOTE) {
563                        i++;
564                        if ((unsigned) i >= lo->lo_phdr_num)
565                                ld_fatal(ld, "not enough room for program"
566                                    " headers");
567                        _WRITE_PHDR(PT_NOTE, os->os_off, os->os_addr,
568                            os->os_size, os->os_size, PF_R, os->os_align);
569                        break;
570                }
571        }
572
573        /*
574         * Create PT_GNU_STACK segment.
575         */
576
577        if (ld->ld_gen_gnustack) {
578                i++;
579                flags = PF_R | PF_W;
580                if (ld->ld_stack_exec)
581                        flags |= PF_X;
582                align = (lo->lo_ec == ELFCLASS32) ? 4 : 8;
583                _WRITE_PHDR(PT_GNU_STACK, 0, 0, 0, 0, flags, align);
584        }
585
586        assert((unsigned) i + 1 == lo->lo_phdr_num);
587
588#undef  _WRITE_PHDR
589}
590
591void
592ld_output_create(struct ld *ld)
593{
594        struct ld_output *lo;
595        const char *fn;
596        GElf_Ehdr eh;
597
598        if (ld->ld_output_file == NULL)
599                fn = "a.out";
600        else
601                fn = ld->ld_output_file;
602
603        lo = ld->ld_output;
604
605        lo->lo_fd = open(fn, O_WRONLY | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
606        if (lo->lo_fd < 0)
607                ld_fatal_std(ld, "can not create output file: open %s", fn);
608
609        if ((lo->lo_elf = elf_begin(lo->lo_fd, ELF_C_WRITE, NULL)) == NULL)
610                ld_fatal(ld, "elf_begin failed: %s", elf_errmsg(-1));
611
612        elf_flagelf(lo->lo_elf, ELF_C_SET, ELF_F_LAYOUT);
613
614        assert(ld->ld_otgt != NULL);
615        lo->lo_ec = elftc_bfd_target_class(ld->ld_otgt);
616        lo->lo_endian = elftc_bfd_target_byteorder(ld->ld_otgt);
617
618        if (gelf_newehdr(lo->lo_elf, lo->lo_ec) == NULL)
619                ld_fatal(ld, "gelf_newehdr failed: %s", elf_errmsg(-1));
620
621        if (gelf_getehdr(lo->lo_elf, &eh) == NULL)
622                ld_fatal(ld, "gelf_getehdr failed: %s", elf_errmsg(-1));
623
624        eh.e_ident[EI_CLASS] = lo->lo_ec;
625        eh.e_ident[EI_DATA] = lo->lo_endian;
626        eh.e_flags = 0;         /* TODO */
627        eh.e_machine = elftc_bfd_target_machine(ld->ld_otgt);
628        eh.e_type = ET_EXEC;    /* TODO */
629        eh.e_version = EV_CURRENT;
630
631        /* Create program headers. */
632        _create_phdr(ld);
633
634        /* Set program header table offset. */
635        eh.e_phoff = gelf_fsize(lo->lo_elf, ELF_T_EHDR, 1, EV_CURRENT);
636        if (eh.e_phoff == 0)
637                ld_fatal(ld, "gelf_fsize failed: %s", elf_errmsg(-1));
638
639        /* Read relocation information from input sections. */
640        ld_reloc_read(ld);
641
642        /* Create output ELF sections. */
643        _create_elf_sections(ld);
644
645        /* Calculate symbol values and indices of the output object. */
646        ld_symbols_update(ld);
647
648        /* Print out link map if requested. */
649        if (ld->ld_print_linkmap)
650                ld_layout_print_linkmap(ld);
651
652        /* Insert section headers table and point e_shoff to it. */
653        eh.e_shoff = _insert_shdr(ld);
654
655        /* Set executable entry point. */
656        eh.e_entry = _find_entry_point(ld);
657
658        /* Save updated ELF header. */
659        if (gelf_update_ehdr(lo->lo_elf, &eh) == 0)
660                ld_fatal(ld, "gelf_update_ehdr failed: %s", elf_errmsg(-1));
661
662        /* Copy and relocate input section data to output section. */
663        _copy_and_reloc_input_sections(ld);
664
665        /* Finalize dynamic symbol section. */
666        if (lo->lo_dynsym != NULL) {
667                ld_symbols_finalize_dynsym(ld);
668                _alloc_section_data_for_symtab(ld, lo->lo_dynsym,
669                    lo->lo_dynsym->os_scn, ld->ld_dynsym);
670        }
671
672        /* Generate section name string table section (.shstrtab). */
673        _create_string_table_section(ld, ".shstrtab", ld->ld_shstrtab, NULL);
674
675        /* Generate symbol table. */
676        _create_symbol_table(ld);
677
678        /*
679         * Update "sh_name", "sh_link" and "sh_info" fields of each section
680         * headers, wherever applicable.
681         */
682        _update_section_header(ld);
683
684        /* Finally write out the output ELF object. */
685        if (elf_update(lo->lo_elf, ELF_C_WRITE) < 0)
686                ld_fatal(ld, "elf_update failed: %s", elf_errmsg(-1));
687}
688
689static uint64_t
690_insert_shdr(struct ld *ld)
691{
692        struct ld_state *ls;
693        struct ld_output *lo;
694        struct ld_output_section *os;
695        uint64_t shoff;
696        int n;
697
698        ls = &ld->ld_state;
699        lo = ld->ld_output;
700
701        if (lo->lo_ec == ELFCLASS32)
702                shoff = roundup(ls->ls_offset, 4);
703        else
704                shoff = roundup(ls->ls_offset, 8);
705
706        ls->ls_offset = shoff;
707
708        n = 0;
709        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
710                if (os->os_scn != NULL)
711                        n++;
712        }
713
714        /* TODO: n + 2 if ld(1) will not create symbol table. */
715        ls->ls_offset += gelf_fsize(lo->lo_elf, ELF_T_SHDR, n + 4, EV_CURRENT);
716
717        return (shoff);
718}
719
720static void
721_add_to_shstrtab(struct ld *ld, const char *name)
722{
723
724        if (ld->ld_shstrtab == NULL) {
725                ld->ld_shstrtab = ld_strtab_alloc(ld);
726                ld_strtab_insert(ld, ld->ld_shstrtab, ".symtab");
727                ld_strtab_insert(ld, ld->ld_shstrtab, ".strtab");
728                ld_strtab_insert(ld, ld->ld_shstrtab, ".shstrtab");
729        }
730
731        ld_strtab_insert(ld, ld->ld_shstrtab, name);
732}
733
734static void
735_update_section_header(struct ld *ld)
736{
737        struct ld_strtab *st;
738        struct ld_output *lo;
739        struct ld_output_section *os;
740        GElf_Shdr sh;
741       
742        lo = ld->ld_output;
743        st = ld->ld_shstrtab;
744        assert(st != NULL && st->st_buf != NULL);
745
746        STAILQ_FOREACH(os, &lo->lo_oslist, os_next) {
747                if (os->os_scn == NULL)
748                        continue;
749
750                if (gelf_getshdr(os->os_scn, &sh) == NULL)
751                        ld_fatal(ld, "gelf_getshdr failed: %s",
752                            elf_errmsg(-1));
753
754                /*
755                 * Set "sh_name" fields of each section headers to point
756                 * to the string table.
757                 */
758                sh.sh_name = ld_strtab_lookup(st, os->os_name);
759
760                /* Update "sh_link" field if need. */
761                if (os->os_link != NULL)
762                        sh.sh_link = elf_ndxscn(os->os_link->os_scn);
763
764                /* Update "sh_info" for dynamic symbol table section. */
765                if (os->os_type == SHT_DYNSYM) {
766                        assert(ld->ld_dynsym != NULL);
767                        sh.sh_info = ld->ld_dynsym->sy_first_nonlocal;
768                }
769
770#if 0
771                printf("name=%s, shname=%#jx, offset=%#jx, size=%#jx, type=%#jx\n",
772                    os->os_name, (uint64_t) sh.sh_name, (uint64_t) sh.sh_offset,
773                    (uint64_t) sh.sh_size, (uint64_t) sh.sh_type);
774#endif
775
776                if (!gelf_update_shdr(os->os_scn, &sh))
777                        ld_fatal(ld, "gelf_update_shdr failed: %s",
778                            elf_errmsg(-1));
779        }
780}
781
782static void
783_create_symbol_table(struct ld *ld)
784{
785        struct ld_state *ls;
786        struct ld_strtab *st;
787        struct ld_output *lo;
788        Elf_Scn *scn_symtab, *scn_strtab;
789        Elf_Data *d;
790        GElf_Shdr sh;
791        size_t strndx;
792
793        ld_symbols_build_symtab(ld);
794
795        ls = &ld->ld_state;
796        lo = ld->ld_output;
797        st = ld->ld_shstrtab;
798        assert(st != NULL && st->st_buf != NULL);
799
800        /*
801         * Create .symtab section.
802         */
803
804        scn_symtab = _create_elf_scn(ld, lo, NULL);
805        scn_strtab = _create_elf_scn(ld, lo, NULL);
806        strndx = elf_ndxscn(scn_strtab);
807
808        if (gelf_getshdr(scn_symtab, &sh) == NULL)
809                ld_fatal(ld, "gelf_getshdr failed: %s", elf_errmsg(-1));
810
811        sh.sh_name = ld_strtab_lookup(st, ".symtab");
812        sh.sh_flags = 0;
813        sh.sh_addr = 0;
814        sh.sh_addralign = (lo->lo_ec == ELFCLASS32) ? 4 : 8;
815        sh.sh_offset = roundup(ls->ls_offset, sh.sh_addralign);
816        sh.sh_entsize = (lo->lo_ec == ELFCLASS32) ? sizeof(Elf32_Sym) :
817            sizeof(Elf64_Sym);
818        sh.sh_size = ld->ld_symtab->sy_size * sh.sh_entsize;
819        sh.sh_type = SHT_SYMTAB;
820        sh.sh_link = strndx;
821        sh.sh_info = ld->ld_symtab->sy_first_nonlocal;
822
823        if (!gelf_update_shdr(scn_symtab, &sh))
824                ld_fatal(ld, "gelf_update_shdr failed: %s", elf_errmsg(-1));
825
826        if ((d = elf_newdata(scn_symtab)) == NULL)
827                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
828
829        d->d_align = sh.sh_addralign;
830        d->d_off = 0;
831        d->d_type = ELF_T_SYM;
832        d->d_size = sh.sh_size;
833        d->d_version = EV_CURRENT;
834        d->d_buf = ld->ld_symtab->sy_buf;
835
836        ls->ls_offset = sh.sh_offset + sh.sh_size;
837
838        /*
839         * Create .strtab section.
840         */
841
842        _create_string_table_section(ld, ".strtab", ld->ld_strtab, scn_strtab);
843}
844
845static void
846_create_string_table_section(struct ld *ld, const char *name,
847    struct ld_strtab *st, Elf_Scn *scn)
848{
849        struct ld_state *ls;
850        struct ld_output *lo;
851        Elf_Data *d;
852        GElf_Shdr sh;
853
854        assert(st != NULL && st->st_buf != NULL);
855        assert(name != NULL);
856
857        ls = &ld->ld_state;
858        lo = ld->ld_output;
859
860        if (scn == NULL)
861                scn = _create_elf_scn(ld, lo, NULL);
862
863        if (strcmp(name, ".shstrtab") == 0) {
864                if (!elf_setshstrndx(lo->lo_elf, elf_ndxscn(scn)))
865                        ld_fatal(ld, "elf_setshstrndx failed: %s",
866                            elf_errmsg(-1));
867        }
868
869        if (gelf_getshdr(scn, &sh) == NULL)
870                ld_fatal(ld, "gelf_getshdr failed: %s", elf_errmsg(-1));
871
872        sh.sh_name = ld_strtab_lookup(ld->ld_shstrtab, name);
873        sh.sh_flags = 0;
874        sh.sh_addr = 0;
875        sh.sh_addralign = 1;
876        sh.sh_offset = ls->ls_offset;
877        sh.sh_size = st->st_size;
878        sh.sh_type = SHT_STRTAB;
879
880        if (!gelf_update_shdr(scn, &sh))
881                ld_fatal(ld, "gelf_update_shdr failed: %s", elf_errmsg(-1));
882
883        if ((d = elf_newdata(scn)) == NULL)
884                ld_fatal(ld, "elf_newdata failed: %s", elf_errmsg(-1));
885
886        d->d_align = 1;
887        d->d_off = 0;
888        d->d_type = ELF_T_BYTE;
889        d->d_size = st->st_size;
890        d->d_version = EV_CURRENT;
891        d->d_buf = st->st_buf;
892
893        ls->ls_offset += st->st_size;
894}
Note: See TracBrowser for help on using the browser.