diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2010-11-18 14:58:01 +0000 |
---|---|---|
committer | Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> | 2013-03-14 22:47:08 +0100 |
commit | daecc9a410a6f23d80daf8ce3afd280fea329e63 (patch) | |
tree | 8d603dd538809431cc01b9e656c827d1f0709052 | |
parent | 20221281b3d67880439cd1d16c151f4528d034fb (diff) |
metag: Add NPTL support
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
44 files changed, 1975 insertions, 95 deletions
diff --git a/include/elf.h b/include/elf.h index 877d08194..cbb4da218 100644 --- a/include/elf.h +++ b/include/elf.h @@ -3184,6 +3184,11 @@ typedef Elf32_Addr Elf32_Conflict; #define R_METAG_RELATIVE 45 #define R_METAG_GLOB_DAT 46 +/* TLS relocations */ +#define R_METAG_TLS_TPOFF 56 +#define R_METAG_TLS_DTPMOD 57 +#define R_METAG_TLS_DTPOFF 58 + #ifdef __cplusplus } #endif diff --git a/ldso/ldso/metag/dl-debug.h b/ldso/ldso/metag/dl-debug.h index 5981d7c73..46c257c5c 100644 --- a/ldso/ldso/metag/dl-debug.h +++ b/ldso/ldso/metag/dl-debug.h @@ -17,11 +17,17 @@ static const char *_dl_reltypes_tab[] = { [6] "R_METAG_REG32OP1", "R_METAG_REG32OP2", "R_METAG_REG32OP3", [9] "R_METAG_REG16OP1", "R_METAG_REG16OP2", "R_METAG_REG16OP3", [12] "R_METAG_REG32OP4", "R_METAG_HIOG", "R_METAG_LOOG", - [30] "R_METAG_VTINHERIT", "R_METAG_VTENTRY", + [30] "R_METAG_GNU_VTINHERIT", "R_METAG_GNU_VTENTRY", [32] "R_METAG_HI16_GOTOFF", "R_METAG_LO16_GOTOFF", [34] "R_METAG_GETSET_GOTOFF", "R_METAG_GETSET_GOT", [36] "R_METAG_HI16_GOTPC", "R_METAG_LO16_GOTPC", [38] "R_METAG_HI16_PLT", "R_METAG_LO16_PLT", [40] "R_METAG_RELBRANCH_PLT", "R_METAG_GOTOFF", [42] "R_METAG_PLT", "R_METAG_COPY", "R_METAG_JMP_SLOT", + [45] "R_METAG_RELATIVE", "R_METAG_GLOB_DAT", "R_METAG_TLS_GD", + [48] "R_METAG_TLS_LDM", "R_METAG_TLS_LDO_HI16", "R_METAG_TLS_LDO_LO16", + [51] "R_METAG_TLS_LDO", "R_METAG_TLS_IE", "R_METAG_TLS_IENONPIC", + [54] "R_METAG_TLS_IENONPIC_HI16", "R_METAG_TLS_IENONPIC_LO16", + [56] "R_METAG_TLS_TPOFF", "R_METAG_TLS_DTPMOD", "R_METAG_TLS_DTPOFF", + [59] "R_METAG_TLS_LE", "R_METAG_TLS_LE_HI16", "R_METAG_TLS_LE_LO16" }; diff --git a/ldso/ldso/metag/dl-startup.h b/ldso/ldso/metag/dl-startup.h index 8dbf747e1..32b2e4b74 100644 --- a/ldso/ldso/metag/dl-startup.h +++ b/ldso/ldso/metag/dl-startup.h @@ -21,6 +21,11 @@ __asm__ ( " CALLR D1RtP,__dl_start\n" " GETL D0Ar2,D1Ar1,[A0StP+#-(1*8)]\n" " GETL D0Ar4,D1Ar3,[A0StP+#-(2*8)]\n" +" ADDT A1LbP,CPC1,#HI(__GLOBAL_OFFSET_TABLE__)\n" +" ADD A1LbP,A1LbP,#LO(__GLOBAL_OFFSET_TABLE__+4)\n" +" ADDT A1LbP,A1LbP,#HI(__dl_fini@GOTOFF)\n" +" ADD A1LbP,A1LbP,#LO(__dl_fini@GOTOFF)\n" +" MOV D0Ar4, A1LbP\n" " SUB A0StP,A0StP,#(2*8)\n" " MOV PC,D0Re0\n" " .size __start,.-__start\n" diff --git a/ldso/ldso/metag/dl-sysdep.h b/ldso/ldso/metag/dl-sysdep.h index 29547cb34..257ca610f 100644 --- a/ldso/ldso/metag/dl-sysdep.h +++ b/ldso/ldso/metag/dl-sysdep.h @@ -36,14 +36,17 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entr #define PAGE_ALIGN (~ADDR_ALIGN) #define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1))) -/* The union of reloc-type-classes where the reloc TYPE is a member. - - TYPE is in the class ELF_RTYPE_CLASS_NOCOPY if it should not be allowed - to resolve to one of the main executable's symbols, as for a COPY - reloc. */ -#define elf_machine_type_class(type) \ - (((((type) == R_METAG_JMP_SLOT)) * ELF_RTYPE_CLASS_PLT) \ - | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to + define the value. + + ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one + of the main executable's symbols, as for a COPY reloc. */ +#define elf_machine_type_class(type) \ + ((((type) == R_METAG_JMP_SLOT || (type) == R_METAG_TLS_DTPMOD \ + || (type) == R_METAG_TLS_DTPOFF || (type) == R_METAG_TLS_TPOFF) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) static inline Elf32_Addr elf_machine_dynamic(Elf32_Ehdr *header) diff --git a/ldso/ldso/metag/elfinterp.c b/ldso/ldso/metag/elfinterp.c index 78434167b..e0f981741 100644 --- a/ldso/ldso/metag/elfinterp.c +++ b/ldso/ldso/metag/elfinterp.c @@ -43,43 +43,36 @@ static inline void __put_unaligned_reloc(unsigned long *addr, unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { - int reloc_type; int symtab_index; char *strtab; char *symname; char *new_addr; char *rel_addr; char **got_addr; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *this_reloc; unsigned long instr_addr; rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL]; this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry); - reloc_type = ELF32_R_TYPE(this_reloc->r_info); - symtab_index = ELF32_R_SYM(this_reloc->r_info); + symtab_index = ELF_R_SYM(this_reloc->r_info); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; symname = strtab + symtab[symtab_index].st_name; - if (unlikely(reloc_type != R_METAG_JMP_SLOT)) { - _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n", - _dl_progname); - _dl_exit(1); - } - /* Address of the jump instruction to fix up. */ instr_addr = ((unsigned long)this_reloc->r_offset + (unsigned long)tpnt->loadaddr); got_addr = (char **)instr_addr; /* Get the address of the GOT entry. */ - new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, + new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); if (unlikely(!new_addr)) { - _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname); + _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", + _dl_progname, symname); _dl_exit(1); } @@ -102,28 +95,28 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) } static int -_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size, - int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) + int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) { int symtab_index; unsigned int i; char *strtab; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *rpnt; /* Parse the relocation information. */ rpnt = (ELF_RELOC *)(intptr_t)rel_addr; rel_size /= sizeof(ELF_RELOC); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; for (i = 0; i < rel_size; i++, rpnt++) { int res; - symtab_index = ELF32_R_SYM(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); debug_sym(symtab, strtab, symtab_index); debug_reloc(symtab, strtab, rpnt); @@ -141,7 +134,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, strtab + symtab[symtab_index].st_name); if (unlikely(res < 0)) { - int reloc_type = ELF32_R_TYPE(rpnt->r_info); + int reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) _dl_dprintf(2, "can't handle reloc type %s\n", @@ -161,8 +154,8 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; int symtab_index; @@ -170,30 +163,35 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long *reloc_addr; unsigned long symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) - unsigned long old_val; + unsigned long old_val = 0; #endif + struct elf_resolve *tls_tpnt = NULL; + struct symbol_ref sym_ref; - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - symtab_index = ELF32_R_SYM(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); symbol_addr = 0; - symname = strtab + symtab[symtab_index].st_name; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; if (symtab_index) { - if (symtab[symtab_index].st_shndx != SHN_UNDEF && - ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) { - symbol_addr = (unsigned long)tpnt->loadaddr; - } else { - symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type), NULL); - } - - if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); - _dl_exit(1); + symname = strtab + symtab[symtab_index].st_name; + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + if (!symbol_addr + && ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS + && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, symname); + return 1; }; - - symbol_addr += rpnt->r_addend; + if (_dl_trace_prelink) { + _dl_debug_lookup(symname, tpnt, &symtab[symtab_index], + &sym_ref, elf_machine_type_class(reloc_type)); + } + tls_tpnt = sym_ref.tpnt; } #if defined (__SUPPORT_LD_DEBUG__) @@ -201,13 +199,21 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, old_val = __get_unaligned_reloc(reloc_addr); #endif +#if defined USE_TLS && USE_TLS + /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' + symbol. This is the case for a static tls variable, so the lookup + module is just that one is referencing the tls variable. */ + if (!tls_tpnt) + tls_tpnt = tpnt; +#endif switch (reloc_type) { case R_METAG_NONE: break; case R_METAG_GLOB_DAT: case R_METAG_JMP_SLOT: case R_METAG_ADDR32: - __put_unaligned_reloc(reloc_addr, symbol_addr); + __put_unaligned_reloc(reloc_addr, + symbol_addr + rpnt->r_addend); break; case R_METAG_COPY: #if defined (__SUPPORT_LD_DEBUG__) @@ -215,11 +221,12 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, _dl_dprintf(_dl_debug_file, "\t%s move %d bytes from %x to %x\n", symname, symtab[symtab_index].st_size, - symbol_addr, reloc_addr); + symbol_addr + rpnt->r_addend, + reloc_addr); #endif _dl_memcpy((char *)reloc_addr, - (char *)symbol_addr, + (char *)symbol_addr + rpnt->r_addend, symtab[symtab_index].st_size); break; case R_METAG_RELATIVE: @@ -227,13 +234,24 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, (unsigned long)tpnt->loadaddr + rpnt->r_addend); break; +#if defined USE_TLS && USE_TLS + case R_METAG_TLS_DTPMOD: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_METAG_TLS_DTPOFF: + *reloc_addr = symbol_addr; + break; + case R_METAG_TLS_TPOFF: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend; + break; +#endif default: return -1; /* Calls _dl_exit(1). */ } #if defined (__SUPPORT_LD_DEBUG__) - if (_dl_debug_reloc && _dl_debug_detail && - (reloc_type != R_METAG_NONE)) { + if (_dl_debug_reloc && _dl_debug_detail && reloc_type != R_METAG_NONE) { unsigned long new_val = __get_unaligned_reloc(reloc_addr); _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, new_val, reloc_addr); @@ -244,8 +262,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; unsigned long *reloc_addr; @@ -253,8 +271,8 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long old_val; #endif - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) old_val = *reloc_addr; @@ -291,9 +309,10 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, int _dl_parse_relocation_information(struct dyn_elf *rpnt, + struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size) { - return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } diff --git a/ldso/ldso/metag/metag_load_tp.S b/ldso/ldso/metag/metag_load_tp.S new file mode 100644 index 000000000..2f00a9fef --- /dev/null +++ b/ldso/ldso/metag/metag_load_tp.S @@ -0,0 +1,20 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +#include <features.h> + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + +#include <sysdep.h> + + .text + .global ___metag_load_tp + .type ___metag_load_tp,@function + +___metag_load_tp: + MOVT D1Ar1,#HI(0x6ffff000) + JUMP D1Ar1,#LO(0x6ffff000) + .size ___metag_load_tp,.-___metag_load_tp + +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index f7083a48b..dbf0b0fd4 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -69,6 +69,7 @@ CSRC- += fork.c getpid.c raise.c #open.c close.c read.c write.c CSRC- += $(if $(findstring =arm=,=$(TARGET_ARCH)=),vfork.c) CSRC- += $(if $(findstring =x86_64=,=$(TARGET_ARCH)=),vfork.c) #CSRC- += $(if $(findstring =mips=y=,=$(TARGET_ARCH)=$(CONFIG_MIPS_O32_ABI)=),waitpid.c) +CSRC- += $(if $(findstring =metag=,=$(TARGET_ARCH)=),vfork.c) endif ifneq ($(ARCH_HAS_DEPRECATED_SYSCALLS),y) # No conversion is needed for new architectures diff --git a/libc/sysdeps/linux/metag/Makefile.arch b/libc/sysdeps/linux/metag/Makefile.arch index 0e6fbfe12..3f11d6da8 100644 --- a/libc/sysdeps/linux/metag/Makefile.arch +++ b/libc/sysdeps/linux/metag/Makefile.arch @@ -7,4 +7,6 @@ CSRC-y := brk.c syscall.c metag.c __syscall_error.c -SSRC-y := _longjmp.S clone.S setjmp.S +SSRC-y := _longjmp.S clone.S setjmp.S vfork.S + +SSRC-$(UCLIBC_HAS_THREADS_NATIVE) += libc-metag_load_tp.S diff --git a/libc/sysdeps/linux/metag/bits/atomic.h b/libc/sysdeps/linux/metag/bits/atomic.h new file mode 100644 index 000000000..64aa50bc4 --- /dev/null +++ b/libc/sysdeps/linux/metag/bits/atomic.h @@ -0,0 +1,66 @@ +/* + * Copyrith (C) 2013 Imagination Technologies Ltd. + * + * Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + * + */ + +#include <stdint.h> +#include <sysdep.h> + +typedef int8_t atomic8_t; +typedef uint8_t uatomic8_t; +typedef int_fast8_t atomic_fast8_t; +typedef uint_fast8_t uatomic_fast8_t; + +typedef int32_t atomic32_t; +typedef uint32_t uatomic32_t; +typedef int_fast32_t atomic_fast32_t; +typedef uint_fast32_t uatomic_fast32_t; + +typedef intptr_t atomicptr_t; +typedef uintptr_t uatomicptr_t; +typedef intmax_t atomic_max_t; +typedef uintmax_t uatomic_max_t; + +void __metag_link_error (void); + +#define atomic_full_barrier() \ + __asm__ __volatile__("": : :"memory") + +/* Atomic compare and exchange. This sequence relies on the kernel to + provide a compare and exchange operation which is atomic. */ + +#define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) + +#define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) + +/* This code uses the kernel helper to do cmpxchg. It relies on the fact + the helper code only clobbers D0Re0. */ +#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \ + ({ register __typeof (oldval) a_current __asm__ ("D1Ar1"); \ + register __typeof (oldval) a_newval __asm__ ("D0Ar2") = (newval); \ + register __typeof (mem) a_ptr __asm__ ("D1Ar3") = (mem); \ + register __typeof (oldval) a_oldval __asm__ ("D0Ar4") = (oldval); \ + __asm__ __volatile__ \ + ("0:\n\t" \ + "GETD %[cur], [%[ptr]]\n\t" \ + "CMP %[cur], %[old]\n\t" \ + "BNE 1f\n\t" \ + "MOVT D1RtP, #0x6fff\n\t" \ + "ADD D1RtP, D1RtP, #0xf040\n\t" \ + "SWAP D1RtP, PC\n\t" \ + "MOV %[cur], %[old]\n\t" \ + "CMP D0Re0, #0\n\t" \ + "BNE 0b\n\t" \ + "1:" \ + : [cur] "=&r" (a_current) \ + : [new] "r" (a_newval), [ptr] "r" (a_ptr), \ + [old] "r" (a_oldval) \ + : "D0Re0", "D1RtP", "cc", "memory"); \ + a_current; }) + +#define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \ + ({ __metag_link_error (); oldval; }) diff --git a/libc/sysdeps/linux/metag/bits/syscalls.h b/libc/sysdeps/linux/metag/bits/syscalls.h index b5c8fc58c..7ea09c2c3 100644 --- a/libc/sysdeps/linux/metag/bits/syscalls.h +++ b/libc/sysdeps/linux/metag/bits/syscalls.h @@ -49,8 +49,9 @@ (__extension__ \ ({unsigned int __sys_result; \ { \ + PREP_ARGS_##nr (args); \ register int _result __asm__ ("D0Re0"), _nr __asm__ ("D1Re0"); \ - LOAD_ARGS_##nr (args); \ + LOAD_ARGS_##nr; \ _nr = (name); \ __asm__ volatile ("SWITCH #0x440001 ! syscall " #name \ : "=r" (_result) \ @@ -68,32 +69,52 @@ #undef INTERNAL_SYSCALL_ERRNO #define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) -#define LOAD_ARGS_0() +#define PREP_ARGS_0() +#define PREP_ARGS_1(a1) \ + int _t1 = (int) (a1); \ + PREP_ARGS_0 () +#define PREP_ARGS_2(a1, a2) \ + int _t2 = (int) (a2); \ + PREP_ARGS_1 (a1) +#define PREP_ARGS_3(a1, a2, a3) \ + int _t3 = (int) (a3); \ + PREP_ARGS_2 (a1, a2) +#define PREP_ARGS_4(a1, a2, a3, a4) \ + int _t4 = (int) (a4); \ + PREP_ARGS_3 (a1, a2, a3) +#define PREP_ARGS_5(a1, a2, a3, a4, a5) \ + int _t5 = (int) (a5); \ + PREP_ARGS_4 (a1, a2, a3, a4) +#define PREP_ARGS_6(a1, a2, a3, a4, a5, a6) \ + int _t6 = (int) (a6); \ + PREP_ARGS_5 (a1, a2, a3, a4, a5) + +#define LOAD_ARGS_0 #define ASM_ARGS_0 -#define LOAD_ARGS_1(a1) \ - register int _a1 __asm__ ("D1Ar1") = (int) (a1); \ - LOAD_ARGS_0 () -#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1) -#define LOAD_ARGS_2(a1, a2) \ - register int _a2 __asm__ ("D0Ar2") = (int) (a2); \ - LOAD_ARGS_1 (a1) -#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2) -#define LOAD_ARGS_3(a1, a2, a3) \ - register int _a3 __asm__ ("D1Ar3") = (int) (a3); \ - LOAD_ARGS_2 (a1, a2) -#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3) -#define LOAD_ARGS_4(a1, a2, a3, a4) \ - register int _a4 __asm__ ("D0Ar4") = (int) (a4); \ - LOAD_ARGS_3 (a1, a2, a3) -#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4) -#define LOAD_ARGS_5(a1, a2, a3, a4, a5) \ - register int _a5 __asm__ ("D1Ar5") = (int) (a5); \ - LOAD_ARGS_4 (a1, a2, a3, a4) -#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5) -#define LOAD_ARGS_6(a1, a2, a3, a4, a5, a6) \ - register int _a6 __asm__ ("D0Ar6") = (int) (a6); \ - LOAD_ARGS_5 (a1, a2, a3, a4, a5) -#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6) +#define LOAD_ARGS_1 \ + register int _a1 __asm__ ("D1Ar1") = (int) (_t1); \ + LOAD_ARGS_0 +#define ASM_ARGS_1 ASM_ARGS_0, "d" (_a1) +#define LOAD_ARGS_2 \ + register int _a2 __asm__ ("D0Ar2") = (int) (_t2); \ + LOAD_ARGS_1 +#define ASM_ARGS_2 ASM_ARGS_1, "d" (_a2) +#define LOAD_ARGS_3 \ + register int _a3 __asm__ ("D1Ar3") = (int) (_t3); \ + LOAD_ARGS_2 +#define ASM_ARGS_3 ASM_ARGS_2, "d" (_a3) +#define LOAD_ARGS_4 \ + register int _a4 __asm__ ("D0Ar4") = (int) (_t4); \ + LOAD_ARGS_3 +#define ASM_ARGS_4 ASM_ARGS_3, "d" (_a4) +#define LOAD_ARGS_5 \ + register int _a5 __asm__ ("D1Ar5") = (int) (_t5); \ + LOAD_ARGS_4 +#define ASM_ARGS_5 ASM_ARGS_4, "d" (_a5) +#define LOAD_ARGS_6 \ + register int _a6 __asm__ ("D0Ar6") = (int) (_t6); \ + LOAD_ARGS_5 +#define ASM_ARGS_6 ASM_ARGS_5, "d" (_a6) #endif /* __ASSEMBLER__ */ #endif /* _BITS_SYSCALLS_H */ diff --git a/libc/sysdeps/linux/metag/clone.S b/libc/sysdeps/linux/metag/clone.S index 8fff56710..d9d836338 100644 --- a/libc/sysdeps/linux/metag/clone.S +++ b/libc/sysdeps/linux/metag/clone.S @@ -8,7 +8,17 @@ #include <asm/errno.h> #include <asm/unistd.h> -/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */ +#define CLONE_VM 0x00000100 +#define CLONE_THREAD 0x00010000 + +#ifdef __PIC__ +#define __CLONE_METAG_LOAD_TP ___metag_load_tp@PLT +#else +#define __CLONE_METAG_LOAD_TP ___metag_load_tp +#endif + +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + pid_t *ptid, struct user_desc *tls, pid_t *ctid); */ .text .global __clone @@ -25,8 +35,12 @@ __clone: MOV D0FrT, D1Ar1 ! do the system call - ! get flags MOV D1Ar1, D1Ar3 + MOV D1Ar3, D1Ar5 + MOV D1Ar5, D0Ar6 + MOV D0Ar6, D0Ar4 + GETD D0Ar4, [A0StP+#-4] + ! new sp is already in D0Ar2 MOV D1Re0, #__NR_clone SWITCH #0x440001 @@ -38,14 +52,36 @@ __clone: ! BRKPNT ! We are the child - ! pick the function arg and call address off the stack and execute - MOV D0Ar2, D0FrT - MOV D1Ar1, D0Ar4 - MOV D1RtP, PC +#ifdef RESET_PID + SETL [A0StP++], D0FrT, D1RtP + MOVT D0FrT, #HI(CLONE_THREAD) + ADD D0FrT, D0FrT, #LO(CLONE_THREAD) + ANDS D0FrT, D0FrT, D1Ar1 + BNZ 3f + MOVT D0FrT, #HI(CLONE_VM) + ADD D0FrT, D0FrT, #LO(CLONE_VM) + ANDS D0FrT, D0FrT, D1Ar1 + BZ 1f + MOV D1Ar1, #-1 + BA 2f +1: MOV D1Re0, #__NR_getpid |