diff options
Diffstat (limited to 'ld')
-rw-r--r-- | ld/Makefile | 25 | ||||
-rw-r--r-- | ld/amd64.c | 9 | ||||
-rw-r--r-- | ld/bigmips_script.ld | 165 | ||||
-rw-r--r-- | ld/i386.c | 13 | ||||
-rw-r--r-- | ld/ld_arch.c | 20 | ||||
-rw-r--r-- | ld/ld_arch.h | 8 | ||||
-rw-r--r-- | ld/ld_dynamic.c | 4 | ||||
-rw-r--r-- | ld/ld_exp.c | 9 | ||||
-rw-r--r-- | ld/ld_file.c | 5 | ||||
-rw-r--r-- | ld/ld_layout.c | 10 | ||||
-rw-r--r-- | ld/ld_output.c | 7 | ||||
-rw-r--r-- | ld/ld_script.c | 41 | ||||
-rw-r--r-- | ld/ld_script.h | 7 | ||||
-rw-r--r-- | ld/ld_script_lexer.l | 5 | ||||
-rw-r--r-- | ld/ld_script_parser.y | 25 | ||||
-rw-r--r-- | ld/ld_strtab.c | 8 | ||||
-rw-r--r-- | ld/ld_symbols.c | 5 | ||||
-rw-r--r-- | ld/littlemips_script.ld | 165 | ||||
-rw-r--r-- | ld/mips.c | 403 | ||||
-rw-r--r-- | ld/mips.h | 29 |
20 files changed, 897 insertions, 66 deletions
diff --git a/ld/Makefile b/ld/Makefile index 64d4eb270b81..2037f01aa91e 100644 --- a/ld/Makefile +++ b/ld/Makefile @@ -1,9 +1,9 @@ -# $Id: Makefile 2910 2013-02-03 06:06:23Z kaiwang27 $ +# $Id: Makefile 3385 2016-01-31 14:26:26Z jkoshy $ TOP= .. PROG= ld -WARNS?= 6 +WARNS?= 5 SRCS= amd64.c \ amd64_script.c \ @@ -24,26 +24,31 @@ SRCS= amd64.c \ ld_path.c \ ld_reloc.c \ ld_script.c \ - ld_script_lexer.l \ - ld_script_parser.y \ ld_strtab.c \ ld_symbols.c \ ld_symver.c \ - y.tab.h + mips.c \ + littlemips_script.c \ + bigmips_script.c -.SUFFIXES: .ld .c -.ld.c: - awk -f ld_script.awk ${.ALLSRC} > ${.TARGET} +LSRC= ld_script_lexer.l +YSRC= ld_script_parser.y -GENSRCS= amd64_script.c i386_script.c +GENSRCS= amd64_script.c i386_script.c littlemips_script.c \ + bigmips_script.c -CLEANFILES+= y.tab.h ${GENSRCS} +CLEANFILES+= ${GENSRCS} DPADD= ${LIBELFTC} ${LIBELF} ${LIBDWARF} LDADD= -lelftc -ldwarf -lelf CFLAGS+= -I. -I${.CURDIR} +YFLAGS= -d NOMAN= +.SUFFIXES: .ld .c +.ld.c: + awk -f ld_script.awk ${.ALLSRC} > ${.TARGET} + .include "${TOP}/mk/elftoolchain.prog.mk" diff --git a/ld/amd64.c b/ld/amd64.c index 565995ba4809..e22520bfebf9 100644 --- a/ld/amd64.c +++ b/ld/amd64.c @@ -35,7 +35,7 @@ #include "ld_utils.h" #include "amd64.h" -ELFTC_VCSID("$Id: amd64.c 2963 2013-08-25 17:29:54Z kaiwang27 $"); +ELFTC_VCSID("$Id: amd64.c 3390 2016-02-05 16:15:58Z emaste $"); static void _create_plt_reloc(struct ld *ld, struct ld_symbol *lsb, uint64_t offset); @@ -115,7 +115,7 @@ _reloc2str(uint64_t r) case 4: return "R_X86_64_PLT32"; case 5: return "R_X86_64_COPY"; case 6: return "R_X86_64_GLOB_DAT"; - case 7: return "R_X86_64_JMP_SLOT"; + case 7: return "R_X86_64_JUMP_SLOT"; case 8: return "R_X86_64_RELATIVE"; case 9: return "R_X86_64_GOTPCREL"; case 10: return "R_X86_64_32"; @@ -133,7 +133,7 @@ _reloc2str(uint64_t r) case 22: return "R_X86_64_GOTTPOFF"; case 23: return "R_X86_64_TPOFF32"; default: - snprintf(s, sizeof(s), "<unkown: %ju>", r); + snprintf(s, sizeof(s), "<unkown: %ju>", (uintmax_t) r); return (s); } } @@ -268,12 +268,11 @@ static void _reserve_gotplt_entry(struct ld *ld, struct ld_symbol *lsb) { struct ld_input_section *is; - uint64_t off; is = _find_and_create_gotplt_section(ld, 1); /* Reserve a GOT entry for PLT. */ - off = ld_input_reserve_ibuf(is, 1); + (void) ld_input_reserve_ibuf(is, 1); /* * Record a R_X86_64_JUMP_SLOT entry for this symbol. Note that diff --git a/ld/bigmips_script.ld b/ld/bigmips_script.ld new file mode 100644 index 000000000000..7f60e19bd9f8 --- /dev/null +++ b/ld/bigmips_script.ld @@ -0,0 +1,165 @@ +/* $Id$ */ + +OUTPUT_FORMAT("elf32-bigmips") +ENTRY(_start) +SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); +SECTIONS { + PROVIDE (__executable_start = 0x00400000); + . = 0x00400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP(*(.init)) + } = 0x00000000 + .plt : { *(.plt) } + .text : + { + _ftext = .; + *(.text .stub .text.* .gnu.linkonce.t.*) + } = 0x00000000 + .fini : + { + KEEP(*(.fini)) + } = 0x00000000 + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : { KEEP(*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + + .tdata : ALIGN(4096) { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + PROVIDE(__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE(__preinit_array_end = .); + PROVIDE(__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE(__init_array_end = .); + PROVIDE(__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE(__fini_array_end = .); + .dynamic : { *(.dynamic) } + .ctors : + { + KEEP(*crtbegin*.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + } + .dtors : + { + KEEP(*crtbegin*.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + } + .jcr : { KEEP(*(.jcr)) } + .got : { *(.got.plt) *(.got) } + .data : + { + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _gp = ALIGN(16) + 0x7ff0; + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + /* Align the end of data segment to page boundary. */ + . = ALIGN(. != 0 ? 4096 : 1); + _edata = .; + PROVIDE(edata = .); + __bss_start = .; + _fbss = .; + .sbss : ALIGN(8) + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE(end = .); + . = DATA_SEGMENT_END (.); + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* DWARF1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF1 Extension */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + /DISCARD/ : { *(.note.GNU-stack) *(.reginfo) } +} diff --git a/ld/i386.c b/ld/i386.c index fab5643f4fe9..760424a017a9 100644 --- a/ld/i386.c +++ b/ld/i386.c @@ -34,7 +34,7 @@ #include "ld_utils.h" #include "i386.h" -ELFTC_VCSID("$Id: i386.c 2967 2013-10-12 23:58:13Z kaiwang27 $"); +ELFTC_VCSID("$Id: i386.c 3391 2016-02-05 19:43:01Z emaste $"); static void _create_plt_reloc(struct ld *ld, struct ld_symbol *lsb, uint64_t offset); @@ -93,7 +93,7 @@ _reloc2str(uint64_t r) case 4: return "R_386_PLT32"; case 5: return "R_386_COPY"; case 6: return "R_386_GLOB_DAT"; - case 7: return "R_386_JMP_SLOT"; + case 7: return "R_386_JUMP_SLOT"; case 8: return "R_386_RELATIVE"; case 9: return "R_386_GOTOFF"; case 10: return "R_386_GOTPC"; @@ -119,7 +119,7 @@ _reloc2str(uint64_t r) case 37: return "R_386_TLS_TPOFF32"; default: - snprintf(s, sizeof(s), "<unkown: %ju>", r); + snprintf(s, sizeof(s), "<unkown: %ju>", (uintmax_t) r); return (s); } } @@ -253,15 +253,14 @@ static void _reserve_gotplt_entry(struct ld *ld, struct ld_symbol *lsb) { struct ld_input_section *is; - uint64_t off; is = _find_and_create_gotplt_section(ld, 1); /* Reserve a GOT entry for PLT. */ - off = ld_input_reserve_ibuf(is, 1); + (void) ld_input_reserve_ibuf(is, 1); /* - * Record a R_386_JMP_SLOT entry for this symbol. Note that + * Record a R_386_JUMP_SLOT entry for this symbol. Note that * we don't need to record the offset (relative to the GOT section) * here, since the PLT relocations will be sorted later and we * will generate GOT section according to the new order. @@ -284,7 +283,7 @@ static void _create_plt_reloc(struct ld *ld, struct ld_symbol *lsb, uint64_t offset) { - ld_reloc_create_entry(ld, ".rel.plt", NULL, R_386_JMP_SLOT, + ld_reloc_create_entry(ld, ".rel.plt", NULL, R_386_JUMP_SLOT, lsb, offset, 0); lsb->lsb_dynrel = 1; diff --git a/ld/ld_arch.c b/ld/ld_arch.c index 33baa132aaab..186beea7cb14 100644 --- a/ld/ld_arch.c +++ b/ld/ld_arch.c @@ -28,8 +28,9 @@ #include "ld_arch.h" #include "i386.h" #include "amd64.h" +#include "mips.h" -ELFTC_VCSID("$Id: ld_arch.c 2515 2012-06-06 23:05:00Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_arch.c 3281 2015-12-11 21:39:23Z kaiwang27 $"); #define LD_DEFAULT_ARCH "amd64" @@ -48,6 +49,7 @@ ld_arch_init(struct ld *ld) i386_register(ld); amd64_register(ld); + mips_register(ld); /* * Find out default arch for output object. @@ -112,7 +114,8 @@ ld_arch_equal(struct ld_arch *a1, struct ld_arch *a2) } void -ld_arch_verify(struct ld *ld, const char *name, int mach) +ld_arch_verify(struct ld *ld, const char *name, int mach, int endian, + unsigned flags) { struct ld_arch *la; struct ld_state *ls; @@ -120,7 +123,7 @@ ld_arch_verify(struct ld *ld, const char *name, int mach) assert(ld->ld_arch != NULL); ls = &ld->ld_state; - if ((la = ld_arch_guess_arch_name(ld, mach)) == NULL) + if ((la = ld_arch_guess_arch_name(ld, mach, endian)) == NULL) ld_fatal(ld, "%s: ELF object architecture %#x not supported", name, mach); @@ -133,11 +136,17 @@ ld_arch_verify(struct ld *ld, const char *name, int mach) ld->ld_arch = la; } + if (ls->ls_first_elf_object) { + la->flags = flags; + } else if (la->merge_flags) { + la->merge_flags(ld, flags); + } + ls->ls_first_elf_object = 0; } struct ld_arch * -ld_arch_guess_arch_name(struct ld *ld, int mach) +ld_arch_guess_arch_name(struct ld *ld, int mach, int endian) { char arch[MAX_ARCH_NAME_LEN + 1]; @@ -152,7 +161,8 @@ ld_arch_guess_arch_name(struct ld *ld, int mach) break; case EM_MIPS: case EM_MIPS_RS3_LE: - snprintf(arch, sizeof(arch), "%s", "mips"); + snprintf(arch, sizeof(arch), "%s", + endian==ELFDATA2MSB ? "bigmips" : "littlemips"); break; case EM_PPC: case EM_PPC64: diff --git a/ld/ld_arch.h b/ld/ld_arch.h index f1f840339138..2165627d68d0 100644 --- a/ld/ld_arch.h +++ b/ld/ld_arch.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ld_arch.h 2913 2013-02-16 07:15:24Z kaiwang27 $ + * $Id: ld_arch.h 3281 2015-12-11 21:39:23Z kaiwang27 $ */ #define MAX_ARCH_NAME_LEN 64 @@ -47,11 +47,13 @@ struct ld_arch { void (*finalize_reloc)(struct ld *, struct ld_input_section *, struct ld_reloc_entry *); void (*finalize_got_and_plt)(struct ld *); + void (*merge_flags)(struct ld *, unsigned flags); int (*is_absolute_reloc)(uint64_t); int (*is_relative_reloc)(uint64_t); unsigned char reloc_is_64bit; unsigned char reloc_is_rela; size_t reloc_entsize; + unsigned flags; /* processor-specific flags */ UT_hash_handle hh; struct ld_arch *alias; }; @@ -59,7 +61,7 @@ struct ld_arch { void ld_arch_init(struct ld *); int ld_arch_equal(struct ld_arch *, struct ld_arch *); struct ld_arch *ld_arch_find(struct ld *, char *); -struct ld_arch *ld_arch_guess_arch_name(struct ld *, int); +struct ld_arch *ld_arch_guess_arch_name(struct ld *, int, int); void ld_arch_set(struct ld *, char *); void ld_arch_set_from_target(struct ld *); -void ld_arch_verify(struct ld *, const char *, int); +void ld_arch_verify(struct ld *, const char *, int, int, unsigned); diff --git a/ld/ld_dynamic.c b/ld/ld_dynamic.c index 371e0caa6677..aa0ab6991d71 100644 --- a/ld/ld_dynamic.c +++ b/ld/ld_dynamic.c @@ -37,7 +37,7 @@ #include "ld_symver.h" #include "ld_strtab.h" -ELFTC_VCSID("$Id: ld_dynamic.c 2965 2013-09-10 02:46:29Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_dynamic.c 3384 2016-01-31 13:12:41Z jkoshy $"); static void _check_dso_needed(struct ld *ld, struct ld_output *lo); static void _create_dynamic(struct ld *ld, struct ld_output *lo); @@ -253,7 +253,7 @@ _create_interp(struct ld *ld, struct ld_output *lo) if ((odb->odb_buf = calloc(odb->odb_size, 1)) == NULL) ld_fatal_std(ld, "calloc"); - strncpy(odb->odb_buf, interp, strlen(interp)); + strncpy((char*) odb->odb_buf, interp, strlen(interp)); odb->odb_buf[strlen(interp)] = '\0'; (void) ld_output_create_section_element(ld, os, OET_DATA_BUFFER, odb, diff --git a/ld/ld_exp.c b/ld/ld_exp.c index 8eb182c1a06e..9c57cd8b24ae 100644 --- a/ld/ld_exp.c +++ b/ld/ld_exp.c @@ -30,7 +30,7 @@ #include "ld_exp.h" #include "ld_layout.h" -ELFTC_VCSID("$Id: ld_exp.c 2526 2012-07-17 17:43:30Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_exp.c 3278 2015-12-11 21:39:13Z kaiwang27 $"); /* * Support routines for ldscript expression. @@ -202,7 +202,7 @@ ld_exp_eval(struct ld* ld, struct ld_exp *le) assert(le != NULL); switch (le->le_op) { case LEOP_ABS: - return (abs(_EXP_EVAL(le->le_e1))); + return (llabs(_EXP_EVAL(le->le_e1))); case LEOP_ADD: return (_EXP_EVAL(le->le_e1) + _EXP_EVAL(le->le_e2)); case LEOP_ADDR: @@ -569,7 +569,8 @@ static int64_t _func_data_segment_align(struct ld *ld, struct ld_exp *le) { struct ld_state *ls; - uint64_t maxpagesize, commonpagesize; + uint64_t maxpagesize; + /* uint64_t commonpagesize; */ /* * TODO: test if align to common page size use less number @@ -577,7 +578,7 @@ _func_data_segment_align(struct ld *ld, struct ld_exp *le) */ ls = &ld->ld_state; maxpagesize = _EXP_EVAL(le->le_e1); - commonpagesize = _EXP_EVAL(le->le_e2); + /* commonpagesize = _EXP_EVAL(le->le_e2); */ return (roundup(ls->ls_loc_counter, maxpagesize) + (ls->ls_loc_counter & (maxpagesize - 1))); diff --git a/ld/ld_file.c b/ld/ld_file.c index 4e9ae0057f72..b55918950f08 100644 --- a/ld/ld_file.c +++ b/ld/ld_file.c @@ -29,7 +29,7 @@ #include "ld_file.h" #include "ld_path.h" -ELFTC_VCSID("$Id: ld_file.c 2930 2013-03-17 22:54:26Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_file.c 3281 2015-12-11 21:39:23Z kaiwang27 $"); /* * Support routines for input file handling. @@ -156,7 +156,8 @@ ld_file_load(struct ld *ld, struct ld_file *lf) ld_fatal(ld, "%s: unknown ELF type %u", ehdr.e_type); } - ld_arch_verify(ld, lf->lf_name, ehdr.e_machine); + ld_arch_verify(ld, lf->lf_name, ehdr.e_machine, ehdr.e_ident[EI_DATA], + ehdr.e_flags); } void diff --git a/ld/ld_layout.c b/ld/ld_layout.c index 11711b2d825a..c9ad07be26e3 100644 --- a/ld/ld_layout.c +++ b/ld/ld_layout.c @@ -39,7 +39,7 @@ #include "ld_symbols.h" #include "ld_strtab.h" -ELFTC_VCSID("$Id: ld_layout.c 2965 2013-09-10 02:46:29Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_layout.c 3276 2015-12-11 21:39:06Z kaiwang27 $"); struct ld_wildcard_match { char *wm_name; @@ -89,10 +89,8 @@ ld_layout_sections(struct ld *ld) struct ld_output *lo; struct ld_script *lds; struct ld_script_cmd *ldc; - struct ld_state *ls; int sections_cmd_exist; - ls = &ld->ld_state; lo = ld->ld_output; lds = ld->ld_scp; @@ -270,10 +268,10 @@ _print_section_layout(struct ld *ld, struct ld_output_section *os) printf(" %-14s", is->is_name); if (lo->lo_ec == ELFCLASS32) printf(" 0x%08jx", (uintmax_t) - os->os_addr + is->is_reloff); + (os->os_addr + is->is_reloff)); else printf(" 0x%016jx", (uintmax_t) - os->os_addr + is->is_reloff); + (os->os_addr + is->is_reloff)); if (is->is_size == 0) printf(" %10s", "0x0"); else @@ -885,7 +883,7 @@ ld_layout_insert_output_section(struct ld *ld, const char *name, } _os = STAILQ_NEXT(os, os_next); - if (_os == NULL && + if (_os != NULL && (_os->os_flags & SHF_ALLOC) != (flags & SHF_ALLOC)) break; } diff --git a/ld/ld_output.c b/ld/ld_output.c index 43ea818da2c8..fc4a7762af04 100644 --- a/ld/ld_output.c +++ b/ld/ld_output.c @@ -36,7 +36,7 @@ #include "ld_strtab.h" #include "ld_symbols.h" -ELFTC_VCSID("$Id: ld_output.c 2965 2013-09-10 02:46:29Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_output.c 3281 2015-12-11 21:39:23Z kaiwang27 $"); static void _alloc_input_section_data(struct ld *ld, Elf_Scn *scn, struct ld_input_section *is); @@ -113,7 +113,7 @@ ld_output_init(struct ld *ld) eh.e_ident[EI_CLASS] = lo->lo_ec; eh.e_ident[EI_DATA] = lo->lo_endian; - eh.e_flags = 0; /* TODO */ + eh.e_flags = ld->ld_arch->flags; eh.e_machine = elftc_bfd_target_machine(ld->ld_otgt); if (ld->ld_dso || ld->ld_pie) eh.e_type = ET_DYN; @@ -916,7 +916,8 @@ ld_output_create(struct ld *ld) ld_input_alloc_internal_section_buffers(ld); /* Finalize PLT and GOT sections. */ - ld->ld_arch->finalize_got_and_plt(ld); + if (ld->ld_arch->finalize_got_and_plt) + ld->ld_arch->finalize_got_and_plt(ld); /* Join and sort dynamic relocation sections. */ _join_and_finalize_dynamic_reloc_sections(ld, lo); diff --git a/ld/ld_script.c b/ld/ld_script.c index 1e3d10437463..685c47d35d26 100644 --- a/ld/ld_script.c +++ b/ld/ld_script.c @@ -30,8 +30,9 @@ #include "ld_script.h" #include "ld_file.h" #include "ld_symbols.h" +#include "ld_output.h" -ELFTC_VCSID("$Id: ld_script.c 2881 2013-01-09 22:46:54Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_script.c 3281 2015-12-11 21:39:23Z kaiwang27 $"); static void _input_file_add(struct ld *ld, struct ld_script_input_file *ldif); static void _overlay_section_free(void *ptr); @@ -145,6 +146,40 @@ ld_script_assign_free(struct ld_script_assign *lda) free(lda); } +static void +_update_variable_section(struct ld *ld, struct ld_script_variable *ldv) +{ + struct ld_output_section *os, *last; + + if (ldv->ldv_os_base) { + /* Get base address of the section. */ + STAILQ_FOREACH(os, &ld->ld_output->lo_oslist, os_next) { + if (strcmp(os->os_name, ldv->ldv_os_base) == 0) { + ldv->ldv_base = os->os_addr; + ldv->ldv_os_ref = ldv->ldv_os_base; + ldv->ldv_os_base = 0; + break; + } + } + } + + if (ldv->ldv_os_ref) { + /* Bind the symbol to the last section. */ + last = 0; + STAILQ_FOREACH(os, &ld->ld_output->lo_oslist, os_next) { + if (! os->os_empty) + last = os; + if (strcmp(os->os_name, ldv->ldv_os_ref) == 0) { + if (last) { + ldv->ldv_symbol->lsb_shndx = elf_ndxscn(last->os_scn); + } + ldv->ldv_os_ref = 0; + break; + } + } + } +} + void ld_script_process_assign(struct ld *ld, struct ld_script_assign *lda) { @@ -170,6 +205,10 @@ ld_script_process_assign(struct ld *ld, struct ld_script_assign *lda) (uintmax_t) ls->ls_loc_counter, (uintmax_t) ldv->ldv_val); ls->ls_loc_counter = (uint64_t) ldv->ldv_val; + + } else if (ldv->ldv_symbol != NULL) { + _update_variable_section(ld, ldv); + ldv->ldv_symbol->lsb_value = ldv->ldv_val + ldv->ldv_base; } lda->lda_res = ldv->ldv_val; } diff --git a/ld/ld_script.h b/ld/ld_script.h index ea862521c883..1de4ce0353e5 100644 --- a/ld/ld_script.h +++ b/ld/ld_script.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: ld_script.h 2881 2013-01-09 22:46:54Z kaiwang27 $ + * $Id: ld_script.h 3281 2015-12-11 21:39:23Z kaiwang27 $ */ enum ld_script_cmd_type { @@ -198,8 +198,11 @@ struct ld_script_sections { struct ld_script_variable { char *ldv_name; /* variable name */ + char *ldv_os_base; /* add base address of this section */ + char *ldv_os_ref; /* link symbol to this section */ struct ld_symbol *ldv_symbol; /* assoicated symbol */ int64_t ldv_val; /* variable value */ + int64_t ldv_base; /* base value */ UT_hash_handle hh; /* hash handle */ }; @@ -242,6 +245,8 @@ struct ld_script { unsigned char lds_vn_name_omitted; /* version node w/o name exists */ struct ld_script_cmd_head lds_c; /* other ldscript cmd list */ struct ld_script_variable *lds_v; /* variable table */ + char *lds_last_os_name; /* last output section */ + char *lds_base_os_name; /* current output section */ }; struct ld_script_cmd *ld_script_assert(struct ld *, struct ld_exp *, char *); diff --git a/ld/ld_script_lexer.l b/ld/ld_script_lexer.l index 4a8ff9a2fdf6..f516da33a637 100644 --- a/ld/ld_script_lexer.l +++ b/ld/ld_script_lexer.l @@ -26,9 +26,9 @@ */ #include "ld.h" -#include "y.tab.h" +#include "ld_script_parser.h" -ELFTC_VCSID("$Id: ld_script_lexer.l 2875 2013-01-09 22:46:03Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_script_lexer.l 3385 2016-01-31 14:26:26Z jkoshy $"); #define YY_NO_UNPUT int lineno = 1; @@ -51,6 +51,7 @@ MATTR \(!?[rRwWxXaAiIlL]+\) %option noyywrap %option never-interactive +%option nounput %% diff --git a/ld/ld_script_parser.y b/ld/ld_script_parser.y index d2ffeeee1aa6..71c913145733 100644 --- a/ld/ld_script_parser.y +++ b/ld/ld_script_parser.y @@ -34,7 +34,7 @@ #include "ld_path.h" #include "ld_exp.h" -ELFTC_VCSID("$Id: ld_script_parser.y 2924 2013-03-17 22:53:36Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_script_parser.y 3281 2015-12-11 21:39:23Z kaiwang27 $"); struct yy_buffer_state; typedef struct yy_buffer_state *YY_BUFFER_STATE; @@ -756,7 +756,10 @@ sections_sub_command ; output_sections_desc - : ident output_section_addr_and_type ':' + : ident output_section_addr_and_type ':' { + /* Remember the name of last output section, needed later for assignment. */ + ld->ld_scp->lds_base_os_name = $1; + } output_section_lma output_section_align output_section_subalign @@ -772,16 +775,18 @@ output_sections_desc $$->ldso_name = $1; $$->ldso_vma = $2->ldl_entry; $$->ldso_type = $2->ldl_next->ldl_entry; - $$->ldso_lma = $4; - $$->ldso_align = $5; - $$->ldso_subalign = $6; - $$->ldso_constraint = $7; + $$->ldso_lma = $5; + $$->ldso_align = $6; + $$->ldso_subalign = $7; + $$->ldso_constraint = $8; memcpy(&$$->ldso_c, &ldso_c, sizeof(ldso_c)); - $$->ldso_region = $11; - $$->ldso_lma_region = $12; - $$->ldso_phdr = ld_script_list_reverse($13); - $$->ldso_fill = $14; + $$->ldso_region = $12; + $$->ldso_lma_region = $13; + $$->ldso_phdr = ld_script_list_reverse($14); + $$->ldso_fill = $15; STAILQ_INIT(&ldso_c); + ld->ld_scp->lds_base_os_name = 0; + ld->ld_scp->lds_last_os_name = $1; } ; diff --git a/ld/ld_strtab.c b/ld/ld_strtab.c index 59f0be2a228a..178f50fae479 100644 --- a/ld/ld_strtab.c +++ b/ld/ld_strtab.c @@ -27,7 +27,7 @@ #include "ld.h" #include "ld_strtab.h" -ELFTC_VCSID("$Id: ld_strtab.c 2965 2013-09-10 02:46:29Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_strtab.c 3279 2015-12-11 21:39:16Z kaiwang27 $"); #define _DEFAULT_STRTAB_SIZE 512 @@ -78,9 +78,6 @@ ld_strtab_free(struct ld_strtab *st) if (st == NULL) return; - free(st->st_buf); - free(st); - if (st->st_pool != NULL) { HASH_ITER(hh, st->st_pool, str, tmp) { HASH_DELETE(hh, st->st_pool, str); @@ -88,6 +85,9 @@ ld_strtab_free(struct ld_strtab *st) free(str); } } + + free(st->st_buf); + free(st); } char * diff --git a/ld/ld_symbols.c b/ld/ld_symbols.c index d49d638089b9..cb034a66b072 100644 --- a/ld/ld_symbols.c +++ b/ld/ld_symbols.c @@ -34,7 +34,7 @@ #include "ld_script.h" #include "ld_strtab.h" -ELFTC_VCSID("$Id: ld_symbols.c 2965 2013-09-10 02:46:29Z kaiwang27 $"); +ELFTC_VCSID("$Id: ld_symbols.c 3281 2015-12-11 21:39:23Z kaiwang27 $"); #define _INIT_SYMTAB_SIZE 128 @@ -171,6 +171,9 @@ ld_symbols_add_variable(struct ld *ld, struct ld_script_variable *ldv, if (hidden) lsb->lsb_other = STV_HIDDEN; lsb->lsb_ref_ndso = 1; + ldv->ldv_symbol = lsb; + ldv->ldv_os_ref = ld->ld_scp->lds_last_os_name; + ldv->ldv_os_base = ld->ld_scp->lds_base_os_name; if (ld->ld_var_symbols == NULL) { ld->ld_var_symbols = malloc(sizeof(*ld->ld_var_symbols)); diff --git a/ld/littlemips_script.ld b/ld/littlemips_script.ld new file mode 100644 index 000000000000..3fe3779a8cb7 --- /dev/null +++ b/ld/littlemips_script.ld @@ -0,0 +1,165 @@ +/* $Id$ */ + +OUTPUT_FORMAT("elf32-littlemips") +ENTRY(_start) +SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); +SECTIONS { + PROVIDE (__executable_start = 0x00400000); + . = 0x00400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP(*(.init)) + } = 0x00000000 + .plt : { *(.plt) } + .text : + { + _ftext = .; + *(.text .stub .text.* .gnu.linkonce.t.*) + } = 0x00000000 + .fini : + { + KEEP(*(.fini)) + } = 0x00000000 + PROVIDE(__etext = .); + PROVIDE(_etext = .); + PROVIDE(etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : { KEEP(*(.eh_frame)) } + .gcc_except_table : { *(.gcc_except_table) } + + .tdata : ALIGN(4096) { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + PROVIDE(__preinit_array_start = .); + .preinit_array : { *(.preinit_array) } + PROVIDE(__preinit_array_end = .); + PROVIDE(__init_array_start = .); + .init_array : { *(.init_array) } + PROVIDE(__init_array_end = .); + PROVIDE(__fini_array_start = .); + .fini_array : { *(.fini_array) } + PROVIDE(__fini_array_end = .); + .dynamic : { *(.dynamic) } + .ctors : + { + KEEP(*crtbegin*.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o ) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*(.ctors)) + } + .dtors : + { + KEEP(*crtbegin*.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend*.o ) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*(.dtors)) + } + .jcr : { KEEP(*(.jcr)) } + .got : { *(.got.plt) *(.got) } + .data : + { + _fdata = .; + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _gp = ALIGN(16) + 0x7ff0; + .sdata : + { + *(.sdata .sdata.* .gnu.linkonce.s.*) + } + /* Align the end of data segment to page boundary. */ + . = ALIGN(. != 0 ? 4096 : 1); + _edata = .; + PROVIDE(edata = .); + __bss_start = .; + _fbss = .; + .sbss : ALIGN(8) + { + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + } + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(32 / 8); + } + . = ALIGN(32 / 8); + _end = .; + PROVIDE(end = .); + . = DATA_SEGMENT_END (.); + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* DWARF1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF1 Extension */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + + /DISCARD/ : { *(.note.GNU-stack) *(.reginfo) } +} diff --git a/ld/mips.c b/ld/mips.c new file mode 100644 index 000000000000..59a92219a223 --- /dev/null +++ b/ld/mips.c @@ -0,0 +1,403 @@ +/*- + * Copyright (c) 2015 Serge Vakulenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ld.h" +#include "ld_arch.h" +#include "ld_dynamic.h" +#include "ld_input.h" +#include "ld_output.h" +#include "ld_reloc.h" +#include "ld_symbols.h" +#include "ld_utils.h" +#include "mips.h" + +#define EF_MIPS_ABI2 0x00000020 /* n32 abi */ +#define EF_MIPS_ABI 0x00007000 /* Application binary interface */ +#define E_MIPS_ABI_O32 0x00001000 /* MIPS 32 bit ABI (UCODE) */ +#define E_MIPS_ABI_O64 0x00002000 /* UCODE MIPS 64 bit ABI */ +#define E_MIPS_ABI_EABI32 0x00003000 /* Embedded ABI for 32-bit */ +#define E_MIPS_ABI_EABI64 0x00004000 /* Embedded ABI for 64-bit */ + +#define EF_MIPS_ASE_MDMX 0x08000000 /* MDMX multimedia extensions */ +#define EF_MIPS_ASE_M16 0x04000000 /* MIPS16e ISA extensions */ +#define EF_MIPS_ASE_MICROMIPS 0x02000000 /* MicroMIPS architecture */ + +#define EF_MIPS_ARCH_1 0x00000000 /* MIPS I instruction set */ +#define EF_MIPS_ARCH_2 0x10000000 /* MIPS II instruction set */ +#define EF_MIPS_ARCH_3 0x20000000 /* MIPS III instruction set */ +#define EF_MIPS_ARCH_4 0x30000000 /* MIPS IV instruction set */ +#define EF_MIPS_ARCH_5 0x40000000 /* Never introduced */ +#define EF_MIPS_ARCH_32 0x50000000 /* Mips32 Revision 1 */ +#define EF_MIPS_ARCH_64 0x60000000 /* Mips64 Revision 1 */ +#define EF_MIPS_ARCH_32R2 0x70000000 /* Mips32 Revision 2 */ +#define EF_MIPS_ARCH_64R2 0x80000000 /* Mips64 Revision 2 */ + +ELFTC_VCSID("$Id$"); + +static void +_scan_reloc(struct ld *ld, struct ld_input_section *is, + struct ld_reloc_entry *lre) +{ + + (void) is; + + switch (lre->lre_type) { + + case R_MIPS_NONE: + case R_MIPS_32: + case R_MIPS_26: + case R_MIPS_PC16: + case R_MIPS_GPREL16: + case R_MIPS_HI16: + case R_MIPS_LO16: + break; + + default: + ld_warn(ld, "can not handle relocation %ju", + lre->lre_type); + break; + } +} + +static void +_process_reloc(struct ld *ld, struct ld_input_section *is, + struct ld_reloc_entry *lre, struct ld_symbol *lsb, uint8_t *buf) +{ + struct ld_output *lo = ld->ld_output; + uint32_t pc, s; + int32_t a, v, la; + static uint64_t gp; + static char gp_name[] = "_gp"; + + assert(lo != NULL); + + pc = lre->lre_offset + is->is_output->os_addr + is->is_reloff; + s = (uint32_t) lsb->lsb_value; + READ_32(buf + lre->lre_offset, a); + + switch (lre->lre_type) { + + case R_MIPS_NONE: + break; + + case R_MIPS_32: + /* 32-bit byte address. */ + v = s + a; + WRITE_32(buf + lre->lre_offset, v); + break; + + case R_MIPS_26: + /* Word address at lower 26 bits. */ + s += (a & 0x3ffffff) << 2; + v = (a & ~0x3ffffff) | ((s >> 2) & 0x3ffffff); + WRITE_32(buf + lre->lre_offset, v); + break; + + case R_MIPS_PC16: + /* PC-relative word address at lower 16 bits. */ + s += ((a & 0xffff) << 2) - pc; + v = (a & ~0xffff) | ((s >> 2) & 0xffff); + WRITE_32(buf + lre->lre_offset, v); + break; + + case R_MIPS_GPREL16: + /* GP-relative byte address at lower 16 bits. */ + if (! gp && ld_symbols_get_value(ld, gp_name, &gp) < 0) + ld_fatal(ld, "symbol _gp is undefined"); + + s += (int16_t)(a & 0xffff) - gp; + v = (a & ~0xffff) | (s & 0xffff); + WRITE_32(buf + lre->lre_offset, v); + break; + + case R_MIPS_HI16: + /* 16-bit high part of address pair. */ + if (! STAILQ_NEXT(lre, lre_next) || + STAILQ_NEXT(lre, lre_next)->lre_type != R_MIPS_LO16) + ld_fatal(ld, "no LO16 after HI16 relocation"); + READ_32(buf + STAILQ_NEXT(lre, lre_next)->lre_offset, la); + s += (a << 16) + (int16_t)la; + v = (a & ~0xffff) | (((s - (int16_t)s) >> 16) & 0xffff); + WRITE_32(buf + lre->lre_offset, v); + break; + + case R_MIPS_LO16: + /* 16-bit low part of address pair. */ + s += (int16_t)a; + v = (a & ~0xffff) | (s & 0xffff); + WRITE_32(buf + lre->lre_offset, v); + break; + + default: + ld_fatal(ld, "Relocation %d not supported", lre->lre_type); + break; + } +} + +/* + * Map flags into a valid MIPS architecture level value. + */ +static unsigned +_map_arch(unsigned flags) +{ + flags &= EF_MIPS_ARCH; + + switch (flags) { + default: + case EF_MIPS_ARCH_1: + return EF_MIPS_ARCH_1; + case EF_MIPS_ARCH_2: + case EF_MIPS_ARCH_3: + case EF_MIPS_ARCH_4: + case EF_MIPS_ARCH_5: + case EF_MIPS_ARCH_32: + case EF_MIPS_ARCH_64: + case EF_MIPS_ARCH_32R2: + case EF_MIPS_ARCH_64R2: + return flags; + } +} + +/* + * Merge architecture levels of two files. + */ +static unsigned +_merge_arch(unsigned old_arch, unsigned new_arch) +{ + unsigned base, extended; + + if (old_arch < new_arch) { + base = old_arch; + extended = new_arch; + } else if (old_arch > new_arch) { + base = new_arch; + extended = old_arch; + } else + return old_arch; + + switch (extended) { + default: + case EF_MIPS_ARCH_1: + case EF_MIPS_ARCH_2: + case EF_MIPS_ARCH_3: + case EF_MIPS_ARCH_4: + case EF_MIPS_ARCH_5: + return extended; + + case EF_MIPS_ARCH_32: + if (base <= EF_MIPS_ARCH_2) + return EF_MIPS_ARCH_32; + return EF_MIPS_ARCH_64; + + case EF_MIPS_ARCH_64: + return EF_MIPS_ARCH_64; + + case EF_MIPS_ARCH_32R2: + if (base <= EF_MIPS_ARCH_2 || base == EF_MIPS_ARCH_32) + return EF_MIPS_ARCH_32R2; + return EF_MIPS_ARCH_64R2; + + case EF_MIPS_ARCH_64R2: + return EF_MIPS_ARCH_64R2; + } +} + +static const char* +_abi_name(int flags) +{ + switch (flags & EF_MIPS_ABI) { + case 0: + return (flags & EF_MIPS_ABI2) ? "N32" : "none"; + case E_MIPS_ABI_O32: + return "O32"; + case E_MIPS_ABI_O64: + return "O64"; + case E_MIPS_ABI_EABI32: + return "EABI32"; + case E_MIPS_ABI_EABI64: + return "EABI64"; + default: + return "Unknown"; + } +} + +/* + * Merge options of application binary interface. + */ +static unsigned +_merge_abi(struct ld *ld, unsigned new_flags) +{ + int old = ld->ld_arch->flags & EF_MIPS_ABI; + int new = new_flags & EF_MIPS_ABI; + + if (old == 0) + return new; + + if (new != old && new != 0) + ld_fatal(ld, "ABI mismatch: linking '%s' module with previous '%s' modules", + _abi_name(new_flags), _abi_name(ld->ld_arch->flags)); + + return old; +} + +/* + * Merge options of application-specific extensions. + */ +static unsigned +_merge_ase(struct ld *ld, unsigned new_flags) +{ + int old_micro = ld->ld_arch->flags & EF_MIPS_ASE_MICROMIPS; + int new_micro = new_flags & EF_MIPS_ASE_MICROMIPS; + int old_m16 = ld->ld_arch->flags & EF_MIPS_ASE_M16; + int new_m16 = new_flags & EF_MIPS_ASE_M16; + + if ((old_m16 && new_micro) || (old_micro && new_m16)) + ld_fatal(ld, "ASE mismatch: linking '%s' module with previous '%s' modules", + new_m16 ? "MIPS16" : "microMIPS", + old_micro ? "microMIPS" : "MIPS16"); + return old_micro | new_micro | old_m16 | new_m16; +} + +/* + * Merge architecture-specific flags of the file to be linked + * into a resulting value for output file. + */ +static void +_merge_flags(struct ld *ld, unsigned new_flags) +{ + struct ld_arch *la = ld->ld_arch; + unsigned value; + + /* At least one .noreorder directive appeared in the source. */ + la->flags |= new_flags & EF_MIPS_NOREORDER; + + /* Merge position-independent flags. */ + if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0) != + ((la->flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)) + ld_warn(ld, "linking PIC files with non-PIC files"); + if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) + la->flags |= EF_MIPS_CPIC; + if (! (new_flags & EF_MIPS_PIC)) + la->flags &= ~EF_MIPS_PIC; + + /* Merge architecture level. */ + value = _merge_arch(_map_arch(la->flags), _map_arch(new_flags)); + la->flags &= ~EF_MIPS_ARCH; + la->flags |= value; + + /* Merge ABI options. */ + value = _merge_abi(ld, new_flags); + la->flags &= ~EF_MIPS_ABI; + la->flags |= value; + + /* Merge application-specific extensions. */ + value = _merge_ase(ld, new_flags); + la->flags &= ~EF_MIPS_ARCH_ASE; + la->flags |= value; +} + +static uint64_t +_get_max_page_size(struct ld *ld) +{ + + (void) ld; + + return 0x1000; +} + +static uint64_t +_get_common_page_size(struct ld *ld) +{ + + (void) ld; + + return 0x1000; +} + +static int +_is_absolute_reloc(uint64_t r) +{ + if (r == R_MIPS_32) + return 1; + + return 0; +} + +static int +_is_relative_reloc(uint64_t r) +{ + if (r == R_MIPS_REL32) + return 1; + + return 0; +} + +void +mips_register(struct ld *ld) +{ + struct ld_arch *mips_little_endian, *mips_big_endian; + + if ((mips_little_endian = calloc(1, sizeof(*mips_little_endian))) == NULL) + ld_fatal_std(ld, "calloc"); + if ((mips_big_endian = calloc(1, sizeof(*mips_big_endian))) == NULL) + ld_fatal_std(ld, "calloc"); + + /* + * Little endian. + */ + snprintf(mips_little_endian->name, sizeof(mips_little_endian->name), "%s", "littlemips"); + + mips_little_endian->script = littlemips_script; + mips_little_endian->get_max_page_size = _get_max_page_size; + mips_little_endian->get_common_page_size = _get_common_page_size; + mips_little_endian->scan_reloc = _scan_reloc; + mips_little_endian->process_reloc = _process_reloc; + mips_little_endian->is_absolute_reloc = _is_absolute_reloc; + mips_little_endian->is_relative_reloc = _is_relative_reloc; + mips_little_endian->merge_flags = _merge_flags; + mips_little_endian->reloc_is_64bit = 0; + mips_little_endian->reloc_is_rela = 0; + mips_little_endian->reloc_entsize = sizeof(Elf32_Rel); + + /* + * Big endian. + */ + snprintf(mips_big_endian->name, sizeof(mips_big_endian->name), "%s", "bigmips"); + + mips_big_endian->script = bigmips_script; + mips_big_endian->get_max_page_size = _get_max_page_size; + mips_big_endian->get_common_page_size = _get_common_page_size; + mips_big_endian->scan_reloc = _scan_reloc; + mips_big_endian->process_reloc = _process_reloc; + mips_big_endian->is_absolute_reloc = _is_absolute_reloc; + mips_big_endian->is_relative_reloc = _is_relative_reloc; + mips_little_endian->merge_flags = _merge_flags; + mips_big_endian->reloc_is_64bit = 0; + mips_big_endian->reloc_is_rela = 0; + mips_big_endian->reloc_entsize = sizeof(Elf32_Rel); + + HASH_ADD_STR(ld->ld_arch_list, name, mips_little_endian); + HASH_ADD_STR(ld->ld_arch_list, name, mips_big_endian); +} diff --git a/ld/mips.h b/ld/mips.h new file mode 100644 index 000000000000..90de4aa7fa94 --- /dev/null +++ b/ld/mips.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2015 Serge Vakulenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +char *littlemips_script; +char *bigmips_script; + +void mips_register(struct ld *); |