summaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
Diffstat (limited to 'ld')
-rw-r--r--ld/Makefile25
-rw-r--r--ld/amd64.c9
-rw-r--r--ld/bigmips_script.ld165
-rw-r--r--ld/i386.c13
-rw-r--r--ld/ld_arch.c20
-rw-r--r--ld/ld_arch.h8
-rw-r--r--ld/ld_dynamic.c4
-rw-r--r--ld/ld_exp.c9
-rw-r--r--ld/ld_file.c5
-rw-r--r--ld/ld_layout.c10
-rw-r--r--ld/ld_output.c7
-rw-r--r--ld/ld_script.c41
-rw-r--r--ld/ld_script.h7
-rw-r--r--ld/ld_script_lexer.l5
-rw-r--r--ld/ld_script_parser.y25
-rw-r--r--ld/ld_strtab.c8
-rw-r--r--ld/ld_symbols.c5
-rw-r--r--ld/littlemips_script.ld165
-rw-r--r--ld/mips.c403
-rw-r--r--ld/mips.h29
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 *);