This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
[PATCH 1a/9] Tilera (and Linux asm-generic) support for glibc
- From: Chris Metcalf <cmetcalf at tilera dot com>
- To: libc-ports at sourceware dot org
- Cc: Arnd Bergmann <arnd at arndb dot de>, Linas Vepstas <linas at codeaurora dot org>, Guan Xuetao <gxt at mprc dot pku dot edu dot cn>, Jonas Bonn <jonas at southpole dot se>, Chen Liqin <liqin dot chen at gmail dot com>
- Date: Fri, 4 Nov 2011 08:14:18 -0400
- Subject: [PATCH 1a/9] Tilera (and Linux asm-generic) support for glibc
- References: <201111031955.pA3Jt3sC024069@farm-0002.internal.tilera.com>
(Resending PATCH 1/9 in three pieces to accommodate mailing-list limits.)
This patch is the basic tile architecture support, without the disassembly
support for backtracing (patch 1b) or Linux support (patch 1c).
2011-11-03 Chris Metcalf <cmetcalf@tilera.com>
* sysdeps/tile/Implies: New file.
* sysdeps/tile/Makefile: New file.
* sysdeps/tile/Versions: New file.
* sysdeps/tile/__longjmp.S: New file.
* sysdeps/tile/__tls_get_addr.S: New file.
* sysdeps/tile/_mcount.S: New file.
* sysdeps/tile/abort-instr.h: New file.
* sysdeps/tile/backtrace.c: New file.
* sysdeps/tile/bits/atomic.h: New file.
* sysdeps/tile/bits/byteswap.h: New file.
* sysdeps/tile/bits/endian.h: New file.
* sysdeps/tile/bits/fenv.h: New file.
* sysdeps/tile/bits/link.h: New file.
* sysdeps/tile/bits/mathdef.h: New file.
* sysdeps/tile/bits/mathinline.h: New file.
* sysdeps/tile/bits/setjmp.h: New file.
* sysdeps/tile/bsd-_setjmp.S: New file.
* sysdeps/tile/bsd-setjmp.S: New file.
* sysdeps/tile/bzero.S: New file.
* sysdeps/tile/dl-lookupcfg.h: New file.
* sysdeps/tile/dl-machine.h: New file.
* sysdeps/tile/dl-runtime.c: New file.
* sysdeps/tile/dl-start.S: New file.
* sysdeps/tile/dl-tls.c: New file.
* sysdeps/tile/dl-tls.h: New file.
* sysdeps/tile/dl-trampoline.S: New file.
* sysdeps/tile/elf/start.S: New file.
* sysdeps/tile/fegetenv.c: New file.
* sysdeps/tile/fegetround.c: New file.
* sysdeps/tile/feholdexcpt.c: New file.
* sysdeps/tile/fesetenv.c: New file.
* sysdeps/tile/fesetround.c: New file.
* sysdeps/tile/feupdateenv.c: New file.
* sysdeps/tile/ffs.c: New file.
* sysdeps/tile/ffsll.c: New file.
* sysdeps/tile/gccframe.h: New file.
* sysdeps/tile/jmpbuf-offsets.h: New file.
* sysdeps/tile/jmpbuf-unwind.h: New file.
* sysdeps/tile/ldsodefs.h: New file.
* sysdeps/tile/libc-tls.c: New file.
* sysdeps/tile/machine-gmon.h: New file.
* sysdeps/tile/nptl/Makefile: New file.
* sysdeps/tile/nptl/pthread_spin_lock.c: New file.
* sysdeps/tile/nptl/pthread_spin_trylock.c: New file.
* sysdeps/tile/nptl/pthreaddef.h: New file.
* sysdeps/tile/nptl/tcb-offsets.sym: New file.
* sysdeps/tile/nptl/tls.h: New file.
* sysdeps/tile/preconfigure: New file.
* sysdeps/tile/s_fma.c: New file.
* sysdeps/tile/s_fmaf.c: New file.
* sysdeps/tile/setjmp.S: New file.
* sysdeps/tile/stackinfo.h: New file.
* sysdeps/tile/sysdep.h: New file.
* sysdeps/tile/tilegx/Makefile: New file.
* sysdeps/tile/tilegx/bits/atomic.h: New file.
* sysdeps/tile/tilegx/bits/wordsize.h: New file.
* sysdeps/tile/tilegx/memchr.c: New file.
* sysdeps/tile/tilegx/memcpy.c: New file.
* sysdeps/tile/tilegx/memset.c: New file.
* sysdeps/tile/tilegx/memusage.h: New file.
* sysdeps/tile/tilegx/rawmemchr.c: New file.
* sysdeps/tile/tilegx/strchr.c: New file.
* sysdeps/tile/tilegx/strchrnul.c: New file.
* sysdeps/tile/tilegx/string-endian.h: New file.
* sysdeps/tile/tilegx/strlen.c: New file.
* sysdeps/tile/tilegx/strrchr.c: New file.
* sysdeps/tile/tilegx/tilegx32/Implies: New file.
* sysdeps/tile/tilegx/tilegx64/Implies: New file.
* sysdeps/tile/tilepro/Implies: New file.
* sysdeps/tile/tilepro/Makefile: New file.
* sysdeps/tile/tilepro/bits/atomic.h: New file.
* sysdeps/tile/tilepro/bits/wordsize.h: New file.
* sysdeps/tile/tilepro/memchr.c: New file.
* sysdeps/tile/tilepro/memcpy.S: New file.
* sysdeps/tile/tilepro/memset.c: New file.
* sysdeps/tile/tilepro/memusage.h: New file.
* sysdeps/tile/tilepro/rawmemchr.c: New file.
* sysdeps/tile/tilepro/strchr.c: New file.
* sysdeps/tile/tilepro/strchrnul.c: New file.
* sysdeps/tile/tilepro/strlen.c: New file.
* sysdeps/tile/tilepro/strrchr.c: New file.
* sysdeps/tile/tls-macros.h: New file.
* sysdeps/tile/tst-audit.h: New file.
diff --git a/sysdeps/tile/Implies b/sysdeps/tile/Implies
new file mode 100644
index 0000000..5b29b26
--- /dev/null
+++ b/sysdeps/tile/Implies
@@ -0,0 +1,2 @@
+ieee754/dbl-64
+ieee754/flt-32
diff --git a/sysdeps/tile/Makefile b/sysdeps/tile/Makefile
new file mode 100644
index 0000000..09a9e36
--- /dev/null
+++ b/sysdeps/tile/Makefile
@@ -0,0 +1,13 @@
+# We don't support long doubles as a distinct type. We don't need to set
+# this variable; it's here mostly for documentational purposes.
+
+long-double-fcts = no
+
+ifeq ($(subdir),gmon)
+sysdep_routines += _mcount
+endif
+
+ifeq ($(subdir),elf)
+# extra shared linker files to link only into dl-allobjs.so
+sysdep-rtld-routines += dl-start __tls_get_addr
+endif
diff --git a/sysdeps/tile/Versions b/sysdeps/tile/Versions
new file mode 100644
index 0000000..b275d7f
--- /dev/null
+++ b/sysdeps/tile/Versions
@@ -0,0 +1,6 @@
+libc {
+ GLIBC_2.12 {
+ # name requested by gcc community.
+ __mcount;
+ }
+}
diff --git a/sysdeps/tile/__longjmp.S b/sysdeps/tile/__longjmp.S
new file mode 100644
index 0000000..60fc919
--- /dev/null
+++ b/sysdeps/tile/__longjmp.S
@@ -0,0 +1,58 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <asm-syntax.h>
+#include <feedback-asm.h>
+#include <arch/spr_def.h>
+
+/* PL to return to via iret in longjmp */
+#define RETURN_PL 0
+
+ .text
+ENTRY (__longjmp)
+
+#define RESTORE(r) { LD r, r0 ; ADDI_PTR r0, r0, REGSIZE }
+ FOR_EACH_CALLEE_SAVED_REG(RESTORE)
+
+ /* Make longjmp(buf, 0) return "1" instead.
+ At the same time, construct our iret context; we set ICS so
+ we can validly load EX_CONTEXT for iret without being
+ interrupted halfway through. */
+ {
+ LD r2, r0 /* retrieve ICS bit from jmp_buf */
+ movei r3, 1
+ CMPEQI r0, r1, 0
+ }
+ {
+ mtspr INTERRUPT_CRITICAL_SECTION, r3
+ shli r2, r2, SPR_EX_CONTEXT_0_1__ICS_SHIFT
+ }
+ {
+ mtspr EX_CONTEXT_0_0, lr
+ ori r2, r2, RETURN_PL
+ }
+ {
+ or r0, r1, r0
+ mtspr EX_CONTEXT_0_1, r2
+ }
+ iret
+ jrp lr /* Keep the backtracer happy. */
+END (__longjmp)
diff --git a/sysdeps/tile/__tls_get_addr.S b/sysdeps/tile/__tls_get_addr.S
new file mode 100644
index 0000000..ca491c5
--- /dev/null
+++ b/sysdeps/tile/__tls_get_addr.S
@@ -0,0 +1,150 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <tls.h>
+
+#ifdef _LP64
+#define LOG_SIZEOF_DTV_T 4
+#else
+#define LOG_SIZEOF_DTV_T 3
+#endif
+
+/* On entry, r0 points to two words, the module and the offset.
+ On return, r0 holds the pointer to the relevant TLS memory.
+ Only registers r25..r29 are clobbered by the call. */
+
+ .text
+ENTRY (__tls_get_addr)
+ {
+ lnk r25
+ ADDI_PTR r27, tp, DTV_OFFSET
+ }
+.Llnk:
+#ifdef __tilegx__
+ {
+ LD_PTR r27, r27 /* r27 = THREAD_DTV() */
+ moveli r26, hw1_last(_rtld_local + TLS_GENERATION_OFFSET - .Llnk)
+ }
+ shl16insli r26, r26, hw0(_rtld_local + TLS_GENERATION_OFFSET - .Llnk)
+ {
+ ADD_PTR r25, r25, r26
+ LD_PTR r26, r0 /* r26 = ti_module */
+ }
+#else
+ {
+ LD_PTR r27, r27 /* r27 = THREAD_DTV() */
+ addli r25, r25, lo16(_rtld_local + TLS_GENERATION_OFFSET - .Llnk)
+ }
+ {
+ auli r25, r25, ha16(_rtld_local + TLS_GENERATION_OFFSET - .Llnk)
+ LD_PTR r26, r0 /* r26 = ti_module */
+ }
+#endif
+ LD_PTR r25, r25 /* r25 = DL(dl_tls_generation) */
+ {
+ LD_PTR r28, r27 /* r28 = THREAD_DTV()->counter */
+ ADDI_PTR r29, r0, __SIZEOF_POINTER__
+ }
+ {
+ LD_PTR r29, r29 /* r29 = ti_offset */
+ CMPEQ r25, r28, r25 /* r25 nonzero if generation OK */
+ shli r28, r26, LOG_SIZEOF_DTV_T /* byte index into dtv array */
+ }
+ {
+ BEQZ r25, .Lslowpath
+ CMPEQI r25, r26, -1 /* r25 nonzero if ti_module invalid */
+ }
+ {
+ BNEZ r25, .Lslowpath
+ ADD_PTR r28, r28, r27 /* pointer into module array */
+ }
+ LD_PTR r26, r28 /* r26 = module TLS pointer */
+ {
+ ADD_PTR r0, r26, r29
+ jrp lr
+ }
+
+.Lslowpath:
+ {
+ ST sp, lr
+ ADDLI_PTR r29, sp, - (25 * REGSIZE)
+ }
+ cfi_offset (lr, 0)
+ {
+ ST r29, sp
+ ADDLI_PTR sp, sp, - (26 * REGSIZE)
+ }
+ cfi_def_cfa_offset (26 * REGSIZE)
+ ADDI_PTR r29, sp, (2 * REGSIZE)
+ { ST r29, r1; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r2; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r3; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r4; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r5; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r6; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r7; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r8; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r9; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r10; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r11; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r12; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r13; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r14; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r15; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r16; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r17; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r18; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r19; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r20; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r21; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r22; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r23; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r24; ADDI_PTR r29, r29, REGSIZE }
+ .hidden __tls_get_addr_slow
+ jal __tls_get_addr_slow
+ ADDI_PTR r29, sp, (2 * REGSIZE)
+ { LD r1, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r2, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r3, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r4, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r5, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r6, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r7, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r8, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r9, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r10, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r11, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r12, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r13, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r14, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r15, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r16, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r17, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r18, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r19, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r20, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r21, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r22, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r23, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r24, r29; ADDLI_PTR sp, sp, (26 * REGSIZE) }
+ cfi_def_cfa_offset (0)
+ LD lr, sp
+ jrp lr
+END (__tls_get_addr)
diff --git a/sysdeps/tile/_mcount.S b/sysdeps/tile/_mcount.S
new file mode 100644
index 0000000..63708a1
--- /dev/null
+++ b/sysdeps/tile/_mcount.S
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work contributed by David Mosberger (davidm@cs.arizona.edu).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Assembly stub to invoke __mcount_internal(). Compiler-generated
+ code calls mcount after executing a function's prologue, placing
+ the "lr" register in "r10" for the call. As a result "lr" is the
+ function that invoked mcount, and "r10" is mcount's caller's
+ caller. However, we have to save all the parameter registers here
+ before invoking _mcount_internal. Callee-save and temporary
+ registers need no special attention. We save r10 and restore it to
+ lr on the way out, to properly handle the case of ENTRY() in
+ assembly code, before lr is saved. We use the name __mcount since
+ the gcc community prefers using the reserved namespace. */
+
+#include <sysdep.h>
+
+ .text
+ENTRY(__mcount)
+ {
+ ST sp, lr
+ ADDI_PTR r29, sp, - (12 * REGSIZE)
+ }
+ cfi_offset (lr, 0)
+ {
+ ADDI_PTR sp, sp, - (13 * REGSIZE)
+ ST r29, sp
+ ADDI_PTR r29, r29, REGSIZE
+ }
+ cfi_def_cfa_offset (13 * REGSIZE)
+ { ST r29, r0; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r1; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r2; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r3; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r4; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r5; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r6; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r7; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r8; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r9; ADDI_PTR r29, r29, REGSIZE }
+ { ST r29, r10; ADDI_PTR r29, r29, REGSIZE; move r0, r10 }
+ {
+ move r1, lr
+ jal __mcount_internal
+ }
+ {
+ ADDI_PTR r29, sp, (2 * REGSIZE)
+ }
+ { LD r0, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r1, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r2, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r3, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r4, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r5, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r6, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r7, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r8, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r9, r29; ADDI_PTR r29, r29, REGSIZE }
+ { LD r10, r29; ADDI_PTR sp, sp, (13 * REGSIZE) }
+ cfi_def_cfa_offset (0)
+ {
+ LD lr, sp
+ }
+ {
+ move lr, r10
+ jrp lr
+ }
+END(__mcount)
+
+#undef mcount
+weak_alias (__mcount, _mcount) /* exported in gmon/Versions */
+weak_alias (__mcount, mcount) /* exported in stdlib/Versions */
diff --git a/sysdeps/tile/abort-instr.h b/sysdeps/tile/abort-instr.h
new file mode 100644
index 0000000..0f57da5
--- /dev/null
+++ b/sysdeps/tile/abort-instr.h
@@ -0,0 +1,2 @@
+/* An instruction which should crash any program is `hlt'. */
+#define ABORT_INSTRUCTION asm ("ill")
diff --git a/sysdeps/tile/backtrace.c b/sysdeps/tile/backtrace.c
new file mode 100644
index 0000000..32ad175
--- /dev/null
+++ b/sysdeps/tile/backtrace.c
@@ -0,0 +1,973 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <execinfo.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/ucontext.h>
+#include <sys/syscall.h>
+#include <arch/abi.h>
+
+#include <jmpbuf-offsets.h>
+#include <tile-desc.h>
+
+/* Reads 'size' bytes from 'address' and writes the data to 'result'.
+ * Returns true if successful, else false (e.g. memory not readable).
+ */
+typedef bool (*BacktraceMemoryReader) (void *result,
+ unsigned long address,
+ unsigned int size, void *extra);
+
+typedef struct
+{
+ /* Current PC. */
+ unsigned long pc;
+
+ /* Current stack pointer value. */
+ unsigned long sp;
+
+ /* Current frame pointer value (i.e. caller's stack pointer) */
+ unsigned long fp;
+
+ /* Internal use only: caller's PC for first frame. */
+ unsigned long initial_frame_caller_pc;
+
+ /* Internal use only: callback to read memory. */
+ BacktraceMemoryReader read_memory_func;
+
+ /* Internal use only: arbitrary argument to read_memory_func. */
+ void *read_memory_func_extra;
+
+} BacktraceIterator;
+
+
+typedef enum
+{
+
+ /* We have no idea what the caller's pc is. */
+ PC_LOC_UNKNOWN,
+
+ /* The caller's pc is currently in lr. */
+ PC_LOC_IN_LR,
+
+ /* The caller's pc can be found by dereferencing the caller's sp. */
+ PC_LOC_ON_STACK
+} CallerPCLocation;
+
+
+typedef enum
+{
+
+ /* We have no idea what the caller's sp is. */
+ SP_LOC_UNKNOWN,
+
+ /* The caller's sp is currently in r52. */
+ SP_LOC_IN_R52,
+
+ /* The caller's sp can be found by adding a certain constant
+ * to the current value of sp.
+ */
+ SP_LOC_OFFSET
+} CallerSPLocation;
+
+
+/* Bit values ORed into CALLER_* values for info ops. */
+enum
+{
+ /* Setting the low bit on any of these values means the info op
+ * applies only to one bundle ago.
+ */
+ ONE_BUNDLE_AGO_FLAG = 1,
+
+ /* Setting this bit on a CALLER_SP_* value means the PC is in LR.
+ * If not set, PC is on the stack.
+ */
+ PC_IN_LR_FLAG = 2,
+
+ /* This many of the low bits of a CALLER_SP_* value are for the
+ * flag bits above.
+ */
+ NUM_INFO_OP_FLAGS = 2,
+
+ /* We cannot have one in the memory pipe so this is the maximum. */
+ MAX_INFO_OPS_PER_BUNDLE = 2
+};
+
+
+/* Internal constants used to define 'info' operands. */
+enum
+{
+ /* 0 and 1 are reserved, as are all negative numbers. */
+
+ CALLER_UNKNOWN_BASE = 2,
+
+ CALLER_SP_IN_R52_BASE = 4,
+
+ CALLER_SP_OFFSET_BASE = 8,
+};
+
+
+/* Current backtracer state describing where it thinks the caller is. */
+typedef struct
+{
+ /*
+ * Public fields
+ */
+
+ /* How do we find the caller's PC? */
+ CallerPCLocation pc_location:8;
+
+ /* How do we find the caller's SP? */
+ CallerSPLocation sp_location:8;
+
+ /* If sp_location == SP_LOC_OFFSET, then caller_sp == sp +
+ * loc->sp_offset. Else this field is undefined.
+ */
+ uint16_t sp_offset;
+
+ /* In the most recently visited bundle a terminating bundle? */
+ bool at_terminating_bundle;
+
+ /*
+ * Private fields
+ */
+
+ /* Will the forward scanner see someone clobbering sp
+ * (i.e. changing it with something other than addi sp, sp, N?)
+ */
+ bool sp_clobber_follows;
+
+ /* Operand to next "visible" info op (no more than one bundle past
+ * the next terminating bundle), or -32768 if none.
+ */
+ int16_t next_info_operand;
+
+ /* Is the info of in next_info_op in the very next bundle? */
+ bool is_next_info_operand_adjacent;
+
+} CallerLocation;
+
+#ifdef __tilegx__
+#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
+#define tile_decoded_instruction tilegx_decoded_instruction
+#define tile_mnemonic tilegx_mnemonic
+#define parse_insn_tile parse_insn_tilegx
+#define TILE_OPC_IRET TILEGX_OPC_IRET
+#define TILE_OPC_ADDI TILEGX_OPC_ADDI
+#define TILE_OPC_ADDLI TILEGX_OPC_ADDLI
+#define TILE_OPC_INFO TILEGX_OPC_INFO
+#define TILE_OPC_INFOL TILEGX_OPC_INFOL
+#define TILE_OPC_JRP TILEGX_OPC_JRP
+#define TILE_OPC_MOVE TILEGX_OPC_MOVE
+#define OPCODE_STORE TILEGX_OPC_ST
+typedef long long bt_int_reg_t;
+#else
+#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE
+#define tile_decoded_instruction tilepro_decoded_instruction
+#define tile_mnemonic tilepro_mnemonic
+#define parse_insn_tile parse_insn_tilepro
+#define TILE_OPC_IRET TILEPRO_OPC_IRET
+#define TILE_OPC_ADDI TILEPRO_OPC_ADDI
+#define TILE_OPC_ADDLI TILEPRO_OPC_ADDLI
+#define TILE_OPC_INFO TILEPRO_OPC_INFO
+#define TILE_OPC_INFOL TILEPRO_OPC_INFOL
+#define TILE_OPC_JRP TILEPRO_OPC_JRP
+#define TILE_OPC_MOVE TILEPRO_OPC_MOVE
+#define OPCODE_STORE TILEPRO_OPC_SW
+typedef int bt_int_reg_t;
+#endif
+
+/* A decoded bundle used for backtracer analysis. */
+struct BacktraceBundle
+{
+ tile_bundle_bits bits;
+ int num_insns;
+ struct tile_decoded_instruction insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE];
+};
+
+
+/* Locates an instruction inside the given bundle that
+ * has the specified mnemonic, and whose first 'num_operands_to_match'
+ * operands exactly match those in 'operand_values'.
+ */
+static const struct tile_decoded_instruction *
+find_matching_insn (const struct BacktraceBundle *bundle,
+ tile_mnemonic mnemonic,
+ const int *operand_values, int num_operands_to_match)
+{
+ int i, j;
+ bool match;
+
+ for (i = 0; i < bundle->num_insns; i++)
+ {
+ const struct tile_decoded_instruction *insn = &bundle->insns[i];
+
+ if (insn->opcode->mnemonic != mnemonic)
+ continue;
+
+ match = true;
+ for (j = 0; j < num_operands_to_match; j++)
+ {
+ if (operand_values[j] != insn->operand_values[j])
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ return insn;
+ }
+
+ return NULL;
+}
+
+/* Does this bundle contain an 'iret' instruction? */
+static inline bool
+bt_has_iret (const struct BacktraceBundle *bundle)
+{
+ return find_matching_insn (bundle, TILE_OPC_IRET, NULL, 0) != NULL;
+}
+
+/* Does this bundle contain an 'addi sp, sp, OFFSET' or
+ * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
+ */
+static bool
+bt_has_addi_sp (const struct BacktraceBundle *bundle, int *adjust)
+{
+ static const int vals[2] = { TREG_SP, TREG_SP };
+
+ const struct tile_decoded_instruction *insn =
+ find_matching_insn (bundle, TILE_OPC_ADDI, vals, 2);
+ if (insn == NULL)
+ insn = find_matching_insn (bundle, TILE_OPC_ADDLI, vals, 2);
+#ifdef __tilegx__
+ if (insn == NULL)
+ insn = find_matching_insn (bundle, TILEGX_OPC_ADDXLI, vals, 2);
+ if (insn == NULL)
+ insn = find_matching_insn (bundle, TILEGX_OPC_ADDXI, vals, 2);
+#endif
+ if (insn == NULL)
+ return false;
+
+ *adjust = insn->operand_values[2];
+ return true;
+}
+
+/* Does this bundle contain any 'info OP' or 'infol OP'
+ * instruction, and if so, what are their OP? Note that OP is interpreted
+ * as an unsigned value by this code since that's what the caller wants.
+ * Returns the number of info ops found.
+ */
+static int
+bt_get_info_ops (const struct BacktraceBundle *bundle,
+ int operands[MAX_INFO_OPS_PER_BUNDLE])
+{
+ int num_ops = 0;
+ int i;
+
+ for (i = 0; i < bundle->num_insns; i++)
+ {
+ const struct tile_decoded_instruction *insn = &bundle->insns[i];
+
+ if (insn->opcode->mnemonic == TILE_OPC_INFO ||
+ insn->opcode->mnemonic == TILE_OPC_INFOL)
+ {
+ operands[num_ops++] = insn->operand_values[0];
+ }
+ }
+
+ return num_ops;
+}
+
+/* Does this bundle contain a jrp instruction, and if so, to which
+ * register is it jumping?
+ */
+static bool
+bt_has_jrp (const struct BacktraceBundle *bundle, int *target_reg)
+{
+ const struct tile_decoded_instruction *insn =
+ find_matching_insn (bundle, TILE_OPC_JRP, NULL, 0);
+ if (insn == NULL)
+ return false;
+
+ *target_reg = insn->operand_values[0];
+ return true;
+}
+
+/* Does this bundle modify the specified register in any way? */
+static bool
+bt_modifies_reg (const struct BacktraceBundle *bundle, int reg)
+{
+ int i, j;
+ for (i = 0; i < bundle->num_insns; i++)
+ {
+ const struct tile_decoded_instruction *insn = &bundle->insns[i];
+
+ if (insn->opcode->implicitly_written_register == reg)
+ return true;
+
+ for (j = 0; j < insn->opcode->num_operands; j++)
+ if (insn->operands[j]->is_dest_reg && insn->operand_values[j] == reg)
+ return true;
+ }
+
+ return false;
+}
+
+/* Does this bundle modify sp? */
+static inline bool
+bt_modifies_sp (const struct BacktraceBundle *bundle)
+{
+ return bt_modifies_reg (bundle, TREG_SP);
+}
+
+/* Does this bundle modify lr? */
+static inline bool
+bt_modifies_lr (const struct BacktraceBundle *bundle)
+{
+ return bt_modifies_reg (bundle, TREG_LR);
+}
+
+/* Does this bundle contain the instruction 'move fp, sp'? */
+static inline bool
+bt_has_move_r52_sp (const struct BacktraceBundle *bundle)
+{
+ static const int vals[2] = { 52, TREG_SP };
+ return find_matching_insn (bundle, TILE_OPC_MOVE, vals, 2) != NULL;
+}
+
+/* Does this bundle contain a store of lr to sp? */
+static inline bool
+bt_has_sw_sp_lr (const struct BacktraceBundle *bundle)
+{
+ static const int vals[2] = { TREG_SP, TREG_LR };
+ return find_matching_insn (bundle, OPCODE_STORE, vals, 2) != NULL;
+}
+
+#ifdef __tilegx__
+/* Track moveli values placed into registers. */
+static inline void
+bt_update_moveli (const struct BacktraceBundle *bundle, int moveli_args[])
+{
+ int i;
+ for (i = 0; i < bundle->num_insns; i++)
+ {
+ const struct tile_decoded_instruction *insn = &bundle->insns[i];
+
+ if (insn->opcode->mnemonic == TILEGX_OPC_MOVELI)
+ {
+ int reg = insn->operand_values[0];
+ moveli_args[reg] = insn->operand_values[1];
+ }
+ }
+}
+
+/* Does this bundle contain an 'add sp, sp, reg' instruction
+ * from a register that we saw a moveli into, and if so, what
+ * is the value in the register?
+ */
+static bool
+bt_has_add_sp (const struct BacktraceBundle *bundle, int *adjust,
+ int moveli_args[])
+{
+ static const int vals[2] = { TREG_SP, TREG_SP };
+
+ const struct tile_decoded_instruction *insn =
+ find_matching_insn (bundle, TILEGX_OPC_ADDX, vals, 2);
+ if (insn)
+ {
+ int reg = insn->operand_values[2];
+ if (moveli_args[reg])
+ {
+ *adjust = moveli_args[reg];
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
+/* Locates the caller's PC and SP for a program starting at the
+ * given address.
+ */
+static void
+find_caller_pc_and_caller_sp (CallerLocation * location,
+ const unsigned long start_pc,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra)
+{
+ /* Have we explicitly decided what the sp is,
+ * rather than just the default?
+ */
+ bool sp_determined = false;
+
+ /* Has any bundle seen so far modified lr? */
+ bool lr_modified = false;
+
+ /* Have we seen a move from sp to fp? */
+ bool sp_moved_to_r52 = false;
+
+ /* Have we seen a terminating bundle? */
+ bool seen_terminating_bundle = false;
+
+ /* Cut down on round-trip reading overhead by reading several
+ * bundles at a time.
+ */
+ tile_bundle_bits prefetched_bundles[32];
+ int num_bundles_prefetched = 0;
+ int next_bundle = 0;
+ unsigned long pc;
+
+#ifdef __tilegx__
+ /* Naively try to track moveli values to support addx for -m32. */
+ int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
+#endif
+
+ /* Default to assuming that the caller's sp is the current sp.
+ * This is necessary to handle the case where we start backtracing
+ * right at the end of the epilog.
+ */
+ location->sp_location = SP_LOC_OFFSET;
+ location->sp_offset = 0;
+
+ /* Default to having no idea where the caller PC is. */
+ location->pc_location = PC_LOC_UNKNOWN;
+
+ /* Don't even try if the PC is not aligned. */
+ if (start_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0)
+ return;
+
+ for (pc = start_pc;; pc += sizeof (tile_bundle_bits))
+ {
+
+ struct BacktraceBundle bundle;
+ int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE];
+ int one_ago, jrp_reg;
+ bool has_jrp;
+
+ if (next_bundle >= num_bundles_prefetched)
+ {
+ /* Prefetch some bytes, but don't cross a page
+ * boundary since that might cause a read failure we
+ * don't care about if we only need the first few
+ * bytes. Note: we don't care what the actual page
+ * size is; using the minimum possible page size will
+ * prevent any problems.
+ */
+ unsigned int bytes_to_prefetch = 4096 - (pc & 4095);
+ if (bytes_to_prefetch > sizeof prefetched_bundles)
+ bytes_to_prefetch = sizeof prefetched_bundles;
+
+ if (!read_memory_func (prefetched_bundles, pc,
+ bytes_to_prefetch, read_memory_func_extra))
+ {
+ if (pc == start_pc)
+ {
+ /* The program probably called a bad
+ * address, such as a NULL pointer.
+ * So treat this as if we are at the
+ * start of the function prolog so the
+ * backtrace will show how we got here.
+ */
+ location->pc_location = PC_LOC_IN_LR;
+ return;
+ }
+
+ /* Unreadable address. Give up. */
+ break;
+ }
+
+ next_bundle = 0;
+ num_bundles_prefetched =
+ bytes_to_prefetch / sizeof (tile_bundle_bits);
+ }
+
+ /* Decode the next bundle. */
+ bundle.bits = prefetched_bundles[next_bundle++];
+#ifdef __BIG_ENDIAN__
+ /*
+ * TILE executes the same bundles in little-endian and big-
+ * endian, also the layout of executables in memory are the
+ * same. But in big-endian, if we load the instructions from
+ * memory by hand (for example, in this case) we get
+ * byte-swapped bundles which TILE will not recognize.
+ * This source file is shared by linux kernel, gdb and glibc,
+ * so we are not able to use le64toh (glibc) or le64_to_cpu
+ * (kernel).
+ */
+ bundle.bits = __builtin_bswap64 (bundle.bits);
+#endif
+ bundle.num_insns = parse_insn_tile (bundle.bits, pc, bundle.insns);
+ num_info_ops = bt_get_info_ops (&bundle, info_operands);
+
+ /* First look at any one_ago info ops if they are interesting,
+ * since they should shadow any non-one-ago info ops.
+ */
+ for (one_ago = (pc != start_pc) ? 1 : 0; one_ago >= 0; one_ago--)
+ {
+ int i;
+ for (i = 0; i < num_info_ops; i++)
+ {
+ int info_operand = info_operands[i];
+ if (info_operand < CALLER_UNKNOWN_BASE)
+ {
+ /* Weird; reserved value, ignore it. */
+ continue;
+ }
+
+ /* Skip info ops which are not in the
+ * "one_ago" mode we want right now.
+ */
+ if (((info_operand & ONE_BUNDLE_AGO_FLAG) != 0)
+ != (one_ago != 0))
+ continue;
+
+ /* Clear the flag to make later checking
+ * easier. */
+ info_operand &= ~ONE_BUNDLE_AGO_FLAG;
+
+ /* Default to looking at PC_IN_LR_FLAG. */
+ if (info_operand & PC_IN_LR_FLAG)
+ location->pc_location = PC_LOC_IN_LR;
+ else
+ location->pc_location = PC_LOC_ON_STACK;
+
+ switch (info_operand)
+ {
+ case CALLER_UNKNOWN_BASE:
+ location->pc_location = PC_LOC_UNKNOWN;
+ location->sp_location = SP_LOC_UNKNOWN;
+ return;
+
+ case CALLER_SP_IN_R52_BASE:
+ case CALLER_SP_IN_R52_BASE | PC_IN_LR_FLAG:
+ location->sp_location = SP_LOC_IN_R52;
+ return;
+
+ default:
+ {
+ const unsigned int val = info_operand
+ - CALLER_SP_OFFSET_BASE;
+ const unsigned int sp_offset =
+ (val >> NUM_INFO_OP_FLAGS) * 8;
+ if (sp_offset < 32768)
+ {
+ /* This is a properly encoded
+ * SP offset. */
+ location->sp_location = SP_LOC_OFFSET;
+ location->sp_offset = sp_offset;
+ return;
+ }
+ else
+ {
+ /* This looked like an SP
+ * offset, but it's outside
+ * the legal range, so this
+ * must be an unrecognized
+ * info operand. Ignore it.
+ */
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (seen_terminating_bundle)
+ {
+ /* We saw a terminating bundle during the previous
+ * iteration, so we were only looking for an info op.
+ */
+ break;
+ }
+
+ if (bundle.bits == 0)
+ {
+ /* Wacky terminating bundle. Stop looping, and hope
+ * we've already seen enough to find the caller.
+ */
+ break;
+ }
+
+ /*
+ * Try to determine caller's SP.
+ */
+
+ if (!sp_determined)
+ {
+ int adjust;
+ if (bt_has_addi_sp (&bundle, &adjust)
+#ifdef __tilegx__
+ || bt_has_add_sp (&bundle, &adjust, moveli_args)
+#endif
+ )
+ {
+ location->sp_location = SP_LOC_OFFSET;
+
+ if (adjust <= 0)
+ {
+ /* We are in prolog about to adjust
+ * SP. */
+ location->sp_offset = 0;
+ }
+ else
+ {
+ /* We are in epilog restoring SP. */
+ location->sp_offset = adjust;
+ }
+
+ sp_determined = true;
+ }
+ else
+ {
+ if (bt_has_move_r52_sp (&bundle))
+ {
+ /* Maybe in prolog, creating an
+ * alloca-style frame. But maybe in
+ * the middle of a fixed-size frame
+ * clobbering r52 with SP.
+ */
+ sp_moved_to_r52 = true;
+ }
+
+ if (bt_modifies_sp (&bundle))
+ {
+ if (sp_moved_to_r52)
+ {
+ /* We saw SP get saved into
+ * r52 earlier (or now), which
+ * must have been in the
+ * prolog, so we now know that
+ * SP is still holding the
+ * caller's sp value.
+ */
+ location->sp_location = SP_LOC_OFFSET;
+ location->sp_offset = 0;
+ }
+ else
+ {
+ /* Someone must have saved
+ * aside the caller's SP value
+ * into r52, so r52 holds the
+ * current value.
+ */
+ location->sp_location = SP_LOC_IN_R52;
+ }
+ sp_determined = true;
+ }
+ }
+
+#ifdef __tilegx__
+ /* Track moveli arguments for -m32 mode. */
+ bt_update_moveli (&bundle, moveli_args);
+#endif
+ }
+
+ if (bt_has_iret (&bundle))
+ {
+ /* This is a terminating bundle. */
+ seen_terminating_bundle = true;
+ continue;
+ }
+
+ /*
+ * Try to determine caller's PC.
+ */
+
+ jrp_reg = -1;
+ has_jrp = bt_has_jrp (&bundle, &jrp_reg);
+ if (has_jrp)
+ seen_terminating_bundle = true;
+
+ if (location->pc_location == PC_LOC_UNKNOWN)
+ {
+ if (has_jrp)
+ {
+ if (jrp_reg == TREG_LR && !lr_modified)
+ {
+ /* Looks like a leaf function, or else
+ * lr is already restored. */
+ location->pc_location = PC_LOC_IN_LR;
+ }
+ else
+ {
+ location->pc_location = PC_LOC_ON_STACK;
+ }
+ }
+ else if (bt_has_sw_sp_lr (&bundle))
+ {
+ /* In prolog, spilling initial lr to stack. */
+ location->pc_location = PC_LOC_IN_LR;
+ }
+ else if (bt_modifies_lr (&bundle))
+ {
+ lr_modified = true;
+ }
+ }
+ }
+}
+
+/* Initializes a backtracer to start from the given location.
+ *
+ * If the frame pointer cannot be determined it is set to -1.
+ *
+ * state: The state to be filled in.
+ * read_memory_func: A callback that reads memory.
+ * read_memory_func_extra: An arbitrary argument to read_memory_func.
+ * pc: The current PC.
+ * lr: The current value of the 'lr' register.
+ * sp: The current value of the 'sp' register.
+ * r52: The current value of the 'r52' register.
+ */
+static void
+backtrace_init (BacktraceIterator * state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ unsigned long pc, unsigned long lr,
+ unsigned long sp, unsigned long r52)
+{
+ CallerLocation location;
+ unsigned long fp, initial_frame_caller_pc;
+
+ /* Find out where we are in the initial frame. */
+ find_caller_pc_and_caller_sp (&location, pc,
+ read_memory_func, read_memory_func_extra);
+
+ switch (location.sp_location)
+ {
+ case SP_LOC_UNKNOWN:
+ /* Give up. */
+ fp = -1;
+ break;
+
+ case SP_LOC_IN_R52:
+ fp = r52;
+ break;
+
+ case SP_LOC_OFFSET:
+ fp = sp + location.sp_offset;
+ break;
+
+ default:
+ /* Give up. */
+ fp = -1;
+ break;
+ }
+
+ /* If the frame pointer is not aligned to the basic word size
+ * something terrible happened and we should mark it as invalid.
+ */
+ if (fp % sizeof (bt_int_reg_t) != 0)
+ fp = -1;
+
+ /* -1 means "don't know initial_frame_caller_pc". */
+ initial_frame_caller_pc = -1;
+
+ switch (location.pc_location)
+ {
+ case PC_LOC_UNKNOWN:
+ /* Give up. */
+ fp = -1;
+ break;
+
+ case PC_LOC_IN_LR:
+ if (lr == 0 || lr % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0)
+ {
+ /* Give up. */
+ fp = -1;
+ }
+ else
+ {
+ initial_frame_caller_pc = lr;
+ }
+ break;
+
+ case PC_LOC_ON_STACK:
+ /* Leave initial_frame_caller_pc as -1,
+ * meaning check the stack.
+ */
+ break;
+
+ default:
+ /* Give up. */
+ fp = -1;
+ break;
+ }
+
+ state->pc = pc;
+ state->sp = sp;
+ state->fp = fp;
+ state->initial_frame_caller_pc = initial_frame_caller_pc;
+ state->read_memory_func = read_memory_func;
+ state->read_memory_func_extra = read_memory_func_extra;
+}
+
+/* Handle the case where the register holds more bits than the VA. */
+static bool
+valid_addr_reg (bt_int_reg_t reg)
+{
+ return ((unsigned long) reg == reg);
+}
+
+/* Advances the backtracing state to the calling frame, returning
+ * true iff successful.
+ */
+static bool
+backtrace_next (BacktraceIterator * state)
+{
+ unsigned long next_fp, next_pc;
+ bt_int_reg_t next_frame[2];
+
+ if (state->fp == -1)
+ {
+ /* No parent frame. */
+ return false;
+ }
+
+ /* Try to read the frame linkage data chaining to the next function. */
+ if (!state->read_memory_func (&next_frame, state->fp, sizeof next_frame,
+ state->read_memory_func_extra))
+ {
+ return false;
+ }
+
+ next_fp = next_frame[1];
+ if (!valid_addr_reg (next_frame[1]) || next_fp % sizeof (bt_int_reg_t) != 0)
+ {
+ /* Caller's frame pointer is suspect, so give up. */
+ return false;
+ }
+
+ if (state->initial_frame_caller_pc != -1)
+ {
+ /* We must be in the initial stack frame and already know the
+ * caller PC.
+ */
+ next_pc = state->initial_frame_caller_pc;
+
+ /* Force reading stack next time, in case we were in the
+ * initial frame. We don't do this above just to paranoidly
+ * avoid changing the struct at all when we return false.
+ */
+ state->initial_frame_caller_pc = -1;
+ }
+ else
+ {
+ /* Get the caller PC from the frame linkage area. */
+ next_pc = next_frame[0];
+ if (!valid_addr_reg (next_frame[0]) || next_pc == 0 ||
+ next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0)
+ {
+ /* The PC is suspect, so give up. */
+ return false;
+ }
+ }
+
+ /* Update state to become the caller's stack frame. */
+ state->pc = next_pc;
+ state->sp = state->fp;
+ state->fp = next_fp;
+
+ return true;
+}
+
+static bool
+bt_read_memory (void *result, unsigned long addr,
+ unsigned int size, void *extra)
+{
+ if ((unsigned long) addr < __getpagesize ())
+ return false; /* Page at zero is never mapped */
+ memcpy (result, (const void *) addr, size);
+ return true;
+}
+
+/* Macro to define a copy of the kernel's __rt_sigreturn function
+ (in arch/tile/kernel/entry.S). If that function is changed,
+ this one needs to be changed to match it. */
+#define _sigreturn_asm(REG, NR) asm( \
+ ".pushsection .text.__rt_sigreturn,\"a\"\n" \
+ ".global __rt_sigreturn\n" \
+ ".type __rt_sigreturn,@function\n" \
+ "__rt_sigreturn:\n" \
+ "moveli " #REG ", " #NR "\n" \
+ "swint1\n" \
+ ".size __rt_sigreturn, . - __rt_sigreturn\n" \
+ ".popsection")
+#define sigreturn_asm(REG, NR) _sigreturn_asm(REG, NR)
+#define SIGRETURN_LEN 16
+sigreturn_asm (TREG_SYSCALL_NR_NAME, __NR_rt_sigreturn);
+extern char __rt_sigreturn[];
+
+/* Store up to SIZE return addresses of the current program state in
+ ARRAY and return the exact number of values stored. */
+int
+__backtrace (void **array, int size)
+{
+ jmp_buf jmpbuf;
+ BacktraceIterator it;
+ int i = 0;
+
+ /* See longjmp.h and bits/setjmp.h for the list of saved registers.
+ JB_PC holds the PC of the call site of setjmp(), i.e. right here.
+ We don't have LR, but we have SP/FP, which the backtrace code
+ can use to locate LR on our stack. */
+ setjmp (jmpbuf);
+ backtrace_init (&it, bt_read_memory, NULL,
+ jmpbuf->__jmpbuf[JB_PC], 0,
+ jmpbuf->__jmpbuf[JB_SP], jmpbuf->__jmpbuf[JB_FP]);
+
+ for (;;)
+ {
+
+ /* Loop going up the stack looking for normal caller frames. */
+ while (i < size && backtrace_next (&it))
+ array[i++] = (void *) it.pc;
+
+ /* We're done, unless this was a signal handler. */
+ if (i >= size || i == 0 ||
+ memcmp ((void *) it.pc, __rt_sigreturn, SIGRETURN_LEN) != 0)
+ break;
+
+ /* It was a signal handler; update the reported PC to point to
+ our copy, since that will be findable with dladdr() and therefore
+ somewhat easier to help understand what actually happened. */
+ array[i - 1] = __rt_sigreturn;
+
+ /* Restart using the registers saved by the signal. */
+ struct ucontext *uc = (struct ucontext *)
+ (it.sp + C_ABI_SAVE_AREA_SIZE + sizeof (struct siginfo));
+
+ backtrace_init (&it, bt_read_memory, NULL,
+ uc->uc_mcontext.pc,
+ uc->uc_mcontext.lr,
+ uc->uc_mcontext.sp, uc->uc_mcontext.gregs[TREG_FP]);
+ array[i++] = (void *) (unsigned long) uc->uc_mcontext.pc;
+ }
+
+ return i;
+}
+
+weak_alias (__backtrace, backtrace)
+libc_hidden_def (__backtrace)
diff --git a/sysdeps/tile/bits/atomic.h b/sysdeps/tile/bits/atomic.h
new file mode 100644
index 0000000..f347a8e
--- /dev/null
+++ b/sysdeps/tile/bits/atomic.h
@@ -0,0 +1,87 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* The sub-architecture headers provide definitions for these macros
+ that work for "int" and "long" size values only:
+
+ atomic_compare_and_exchange_val_acq()
+ atomic_exchange_acq()
+ atomic_exchange_and_add()
+ atomic_and_val()
+ atomic_or_val()
+ atomic_decrement_if_positive() [tilegx only]
+
+ Here we provide generic definitions true for all Tilera chips. */
+
+#include <stdint.h>
+#include <features.h>
+
+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 int64_t atomic64_t;
+typedef uint64_t uatomic64_t;
+typedef int_fast64_t atomic_fast64_t;
+typedef uint_fast64_t uatomic_fast64_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* Barrier macro. */
+#define atomic_full_barrier() __insn_mf ()
+
+/* APIs with "release" semantics. */
+#define atomic_compare_and_exchange_val_rel(mem, n, o) \
+ ({ \
+ atomic_full_barrier (); \
+ atomic_compare_and_exchange_val_acq ((mem), (n), (o)); \
+ })
+#define atomic_compare_and_exchange_bool_rel(mem, n, o) \
+ ({ \
+ atomic_full_barrier (); \
+ atomic_compare_and_exchange_bool_acq ((mem), (n), (o)); \
+ })
+#define atomic_exchange_rel(mem, n) \
+ ({ \
+ atomic_full_barrier (); \
+ atomic_exchange_acq ((mem), (n)); \
+ })
+
+/* Various macros that should just be synonyms. */
+#define catomic_exchange_and_add atomic_exchange_and_add
+#define atomic_and(mem, mask) ((void) atomic_and_val ((mem), (mask)))
+#define catomic_and atomic_and
+#define atomic_or(mem, mask) ((void) atomic_or_val ((mem), (mask)))
+#define catomic_or atomic_or
+
+/* atomic_bit_test_set in terms of atomic_or_val. */
+#define atomic_bit_test_set(mem, bit) \
+ ({ __typeof (*(mem)) __att0_mask = ((__typeof (*(mem))) 1 << (bit)); \
+ atomic_or_val ((mem), __att0_mask) & __att0_mask; })
+
+/*
+ * This non-existent symbol is called for unsupporrted sizes,
+ * indicating a bug in the caller.
+ */
+extern int __atomic_error_bad_argument_size(void)
+ __attribute__ ((warning ("bad sizeof atomic argument")));
diff --git a/sysdeps/tile/bits/byteswap.h b/sysdeps/tile/bits/byteswap.h
new file mode 100644
index 0000000..6858a30
--- /dev/null
+++ b/sysdeps/tile/bits/byteswap.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if !defined _BYTESWAP_H && !defined _NETINET_IN_H && !defined _ENDIAN_H
+# error "Never use <bits/byteswap.h> directly; include <byteswap.h> instead."
+#endif
+
+#ifndef _BITS_BYTESWAP_H
+#define _BITS_BYTESWAP_H 1
+
+/* gcc __builtin_bswap64() can constant-fold, etc, so always use it. */
+#define __bswap_16(x) ((unsigned short)(__builtin_bswap32(x) >> 16))
+#define __bswap_32(x) ((unsigned int)__builtin_bswap32(x))
+#define __bswap_64(x) ((unsigned long long)__builtin_bswap64(x))
+
+#define __bswap_constant_16(x) __bswap_16(x)
+#define __bswap_constant_32(x) __bswap_32(x)
+#define __bswap_constant_64(x) __bswap_64(x)
+
+#endif /* _BITS_BYTESWAP_H */
diff --git a/sysdeps/tile/bits/endian.h b/sysdeps/tile/bits/endian.h
new file mode 100644
index 0000000..43d94bb
--- /dev/null
+++ b/sysdeps/tile/bits/endian.h
@@ -0,0 +1,13 @@
+/* Set endianness for tile. */
+
+#ifndef _ENDIAN_H
+# error "Never use <bits/endian.h> directly; include <endian.h> instead."
+#endif
+
+#if defined __BIG_ENDIAN__
+# define __BYTE_ORDER __BIG_ENDIAN
+#elif defined __LITTLE_ENDIAN__
+# define __BYTE_ORDER __LITTLE_ENDIAN
+#else
+# error "Endianness not declared!!"
+#endif
diff --git a/sysdeps/tile/bits/fenv.h b/sysdeps/tile/bits/fenv.h
new file mode 100644
index 0000000..feb41fa
--- /dev/null
+++ b/sysdeps/tile/bits/fenv.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 1997, 1998, 1999, 2008 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _FENV_H
+# error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
+#endif
+
+/* The TILE-Gx hardware does not provide floating-point exception
+ handling, and TILEPro does not support any floating-point operations. */
+#define FE_ALL_EXCEPT 0
+
+/* TILE-Gx supports only round-to-nearest. The software
+ floating-point support also acts this way. */
+enum
+ {
+ FE_TONEAREST = 1,
+#define FE_TONEAREST FE_TONEAREST
+ };
+
+/* Type representing exception flags (if there were any). */
+typedef unsigned int fexcept_t;
+
+/* Type representing floating-point environment. */
+typedef unsigned int fenv_t;
+
+/* If the default argument is used we use this value. */
+#define FE_DFL_ENV ((__const fenv_t *) -1l)
diff --git a/sysdeps/tile/bits/link.h b/sysdeps/tile/bits/link.h
new file mode 100644
index 0000000..2d48cff
--- /dev/null
+++ b/sysdeps/tile/bits/link.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _LINK_H
+# error "Never include <bits/link.h> directly; use <link.h> instead."
+#endif
+
+#define __need_int_reg_t
+#include <arch/abi.h>
+
+
+/* Registers for entry into PLT. */
+typedef struct La_tile_regs
+{
+ __uint_reg_t lr_reg[10];
+} La_tile_regs;
+
+/* Return values for calls from PLT. */
+typedef struct La_tile_retval
+{
+ /* Up to ten registers can be used for a return value (e.g. small struct). */
+ __uint_reg_t lrv_reg[10];
+} La_tile_retval;
+
+
+__BEGIN_DECLS
+
+extern ElfW(Addr) la_tile_gnu_pltenter (ElfW(Sym) *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ La_tile_regs *__regs,
+ unsigned int *__flags,
+ const char *__symname,
+ long int *__framesizep);
+extern ElfW(Addr) la_tile_gnu_pltexit (ElfW(Sym) *__sym, unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ const La_tile_regs *__inregs,
+ La_tile_retval *__outregs,
+ const char *__symname);
+
+__END_DECLS
diff --git a/sysdeps/tile/bits/mathdef.h b/sysdeps/tile/bits/mathdef.h
new file mode 100644
index 0000000..7c7ef5d
--- /dev/null
+++ b/sysdeps/tile/bits/mathdef.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#if !defined _MATH_H && !defined _COMPLEX_H
+# error "Never use <bits/mathdef.h> directly; include <math.h> instead"
+#endif
+
+#if defined __USE_ISOC99 && defined _MATH_H && !defined _MATH_H_MATHDEF
+# define _MATH_H_MATHDEF 1
+
+/* "float" and "double" expressions evaluated as "float" and "double". */
+typedef float float_t;
+typedef double double_t;
+
+/* The values returned by `ilogb' for 0 and NaN respectively. */
+# define FP_ILOGB0 (-2147483647)
+# define FP_ILOGBNAN (2147483647)
+
+/* The GCC 4.6 compiler will define __FP_FAST_FMA{,F,L} if the fma{,f,l}
+ builtins are supported. */
+# if __FP_FAST_FMA
+# define FP_FAST_FMA 1
+# endif
+
+# if __FP_FAST_FMAF
+# define FP_FAST_FMAF 1
+# endif
+
+# if __FP_FAST_FMAL
+# define FP_FAST_FMAL 1
+# endif
+
+#endif /* ISO C99 */
diff --git a/sysdeps/tile/bits/mathinline.h b/sysdeps/tile/bits/mathinline.h
new file mode 100644
index 0000000..db29fdb
--- /dev/null
+++ b/sysdeps/tile/bits/mathinline.h
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _MATH_H
+# error "Never use <bits/mathinline.h> directly; include <math.h> instead."
+#endif
+
+#ifndef __extern_always_inline
+# define __MATH_INLINE __inline
+#else
+# define __MATH_INLINE __extern_always_inline
+#endif
+
+
+#if defined __USE_ISOC99 && defined __GNUC__
+
+/* Test for negative number. Used in the signbit() macro. */
+__MATH_INLINE int
+__NTH (__signbitf (float __x))
+{
+ __extension__ union { float __f; int __i; } __u = { __f: __x };
+ return __u.__i < 0;
+}
+__MATH_INLINE int
+__NTH (__signbit (double __x))
+{
+ __extension__ union { double __d; long long __i; } __u = { __d: __x };
+ return __u.__i < 0;
+}
+
+#endif
diff --git a/sysdeps/tile/bits/setjmp.h b/sysdeps/tile/bits/setjmp.h
new file mode 100644
index 0000000..4961259
--- /dev/null
+++ b/sysdeps/tile/bits/setjmp.h
@@ -0,0 +1,37 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Define the machine-dependent type `jmp_buf'. TILE version. */
+#ifndef _BITS_SETJMP_H
+#define _BITS_SETJMP_H 1
+
+#if !defined _SETJMP_H && !defined _PTHREAD_H
+# error "Never include <bits/setjmp.h> directly; use <setjmp.h> instead."
+#endif
+
+#ifndef _ASM
+
+#define __need_int_reg_t
+#include <arch/abi.h>
+
+typedef __uint_reg_t __jmp_buf[32];
+
+#endif
+
+#endif /* bits/setjmp.h */
diff --git a/sysdeps/tile/bsd-_setjmp.S b/sysdeps/tile/bsd-_setjmp.S
new file mode 100644
index 0000000..4e6a2da
--- /dev/null
+++ b/sysdeps/tile/bsd-_setjmp.S
@@ -0,0 +1 @@
+/* _setjmp is in setjmp.S */
diff --git a/sysdeps/tile/bsd-setjmp.S b/sysdeps/tile/bsd-setjmp.S
new file mode 100644
index 0000000..1da848d
--- /dev/null
+++ b/sysdeps/tile/bsd-setjmp.S
@@ -0,0 +1 @@
+/* setjmp is in setjmp.S */
diff --git a/sysdeps/tile/bzero.S b/sysdeps/tile/bzero.S
new file mode 100644
index 0000000..12d8aba
--- /dev/null
+++ b/sysdeps/tile/bzero.S
@@ -0,0 +1,30 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+
+ .text
+ENTRY(__bzero)
+ {
+ move r2, r1
+ move r1, zero
+ }
+ j __memset
+END(__bzero)
+weak_alias (__bzero, bzero)
diff --git a/sysdeps/tile/dl-lookupcfg.h b/sysdeps/tile/dl-lookupcfg.h
new file mode 100644
index 0000000..e1a5b26
--- /dev/null
+++ b/sysdeps/tile/dl-lookupcfg.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define DL_UNMAP_IS_SPECIAL
+
+#include_next <dl-lookupcfg.h>
+
+struct link_map;
+
+void internal_function _dl_unmap (struct link_map *map);
+
+#define DL_UNMAP(map) _dl_unmap (map)
diff --git a/sysdeps/tile/dl-machine.h b/sysdeps/tile/dl-machine.h
new file mode 100644
index 0000000..8f2ed4b
--- /dev/null
+++ b/sysdeps/tile/dl-machine.h
@@ -0,0 +1,1213 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work contributed by by Carl Pederson & Martin Schwidefsky.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef dl_machine_h
+#define dl_machine_h
+
+#ifdef __tilegx__
+#define ELF_MACHINE_NAME "tilegx"
+#else
+#define ELF_MACHINE_NAME "tilepro"
+#endif
+
+#include <sys/param.h>
+#include <string.h>
+#include <link.h>
+#include <bits/wordsize.h>
+#include <arch/icache.h>
+
+#include <tile-desc.h>
+
+/* Return nonzero iff ELF header is compatible with the running host. */
+static inline int
+elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
+{
+#if defined __tilegx__
+ if (ehdr->e_machine != EM_TILEGX)
+ return 0;
+# if __WORDSIZE == 32
+ return (ehdr->e_ident[EI_CLASS] == ELFCLASS32);
+# else
+ return (ehdr->e_ident[EI_CLASS] == ELFCLASS64);
+# endif
+#elif defined __tilepro__
+ return ehdr->e_machine == EM_TILEPRO;
+#else
+# error "Unknown tile architecture."
+#endif
+}
+
+
+/* Return the link-time address of _DYNAMIC. Conveniently, this is the
+ first element of the GOT. This must be inlined in a function which
+ uses global data. */
+
+static inline ElfW(Addr)
+elf_machine_dynamic (void)
+{
+ ElfW(Addr) *got;
+
+#ifdef __tilegx__
+ ElfW(Addr) tmp;
+ asm( " { lnk %0; moveli %1, hw2_last(_GLOBAL_OFFSET_TABLE_ - 1f) }\n"
+ "1: shl16insli %1, %1, hw1(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " shl16insli %1, %1, hw0(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " add %0, %0, %1"
+ : "=r" (got), "=r" (tmp));
+#else
+ asm( " lnk %0\n"
+ "1: addli %0, %0, lo16(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " auli %0, %0, ha16(_GLOBAL_OFFSET_TABLE_ - 1b)"
+ : "=r" (got));
+#endif
+
+ return *got;
+}
+
+
+/* Return the run-time load address of the shared object. */
+static inline ElfW(Addr)
+elf_machine_load_address (void)
+{
+ ElfW(Addr) *got;
+ ElfW(Addr) dynamic;
+
+#ifdef __tilegx__
+ ElfW(Addr) tmp;
+ asm( " lnk %2\n"
+ "1: {\n"
+ " moveli %0, hw2_last(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " moveli %1, hw2_last(_DYNAMIC - 1b)\n"
+ " }\n"
+ " {\n"
+ " shl16insli %0, %0, hw1(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " shl16insli %1, %1, hw1(_DYNAMIC - 1b)\n"
+ " }\n"
+ " {\n"
+ " shl16insli %0, %0, hw0(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " shl16insli %1, %1, hw0(_DYNAMIC - 1b)\n"
+ " }\n"
+ " {\n"
+ " add %0, %0, %2\n"
+ " add %1, %1, %2\n"
+ " }"
+ : "=r" (got), "=r" (dynamic), "=r" (tmp));
+#else
+ asm( " lnk %0\n"
+ "1: {\n"
+ " addli %0, %0, lo16(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " addli %1, %0, lo16(_DYNAMIC - 1b)\n"
+ " }\n"
+ " {\n"
+ " auli %0, %0, ha16(_GLOBAL_OFFSET_TABLE_ - 1b)\n"
+ " auli %1, %1, ha16(_DYNAMIC - 1b)\n"
+ " }\n"
+ : "=r" (got), "=r" (dynamic));
+#endif
+
+ return dynamic - *got;
+}
+
+/* Flush some range of the instruction cache. If invoked prior to
+ actually setting dl_pagesize, we conservatively use 4KB, which
+ is the smallest page size we could plausibly be running with. */
+static inline void
+_dl_flush_icache (const void *addr, unsigned long size)
+{
+ invalidate_icache (addr, size, GLRO(dl_pagesize) ? : 4096);
+}
+
+/* Set up the loaded object described by L so its unrelocated PLT
+ entries will jump to the on-demand fixup code in dl-runtime.c.
+ We use the first few PLT slots to trampoline to the resolve function.
+
+ The TILEPro header looks like:
+
+ {
+ moveli r28, lo16(MODULE)
+ rli r29, r29, 16
+ }
+ {
+ auli r28, r28, ha16(MODULE)
+ j _dl_runtime_{resolve,profile}
+ }
+
+ (We use rli rather than shri so that we could theoretically support
+ more than 64K PLT entries by having a fake PLT entry every 64K
+ entries that sets the low 16 bits of r29 and then jumps here.
+ With rotate, no bits are lost.)
+
+ The 32-bit TILE-Gx header looks like:
+
+ {
+ moveli r28, hw1_last(MODULE)
+ moveli r27, hw1_last(_dl_runtime_{resolve,profile})
+ }
+ {
+ shl16insli r28, r28, hw0(MODULE)
+ shl16insli r27, r27, hw0(_dl_runtime_{resolve,profile})
+ }
+ {
+ jr r27
+ info 10 ## SP not offset, return PC in LR
+ }
+
+ The 64-bit TILE-Gx header is the same but extends to 48-bit VAs:
+
+ {
+ moveli r28, hw2_last(MODULE)
+ moveli r27, hw2_last(_dl_runtime_{resolve,profile})
+ }
+ {
+ shl16insli r28, r28, hw1(MODULE)
+ shl16insli r27, r27, hw1(_dl_runtime_{resolve,profile})
+ }
+ {
+ shl16insli r28, r28, hw0(MODULE)
+ shl16insli r27, r27, hw0(_dl_runtime_{resolve,profile})
+ }
+ {
+ jr r27
+ info 10 ## SP not offset, return PC in LR
+ }
+*/
+
+static inline int __attribute__ ((unused))
+old_elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+{
+ extern void _dl_runtime_resolve (ElfW(Word));
+ extern void _dl_runtime_profile (ElfW(Word));
+ ElfW(Addr) rfunc;
+ tile_bundle_bits *plt_base, *plt;
+ plt = plt_base = (tile_bundle_bits *) D_PTR (l, l_info[DT_PLTGOT]);
+
+ if (__builtin_expect (profile, 0))
+ {
+ rfunc = (ElfW(Addr)) &_dl_runtime_profile;
+
+ if (GLRO(dl_profile) != NULL
+ && _dl_name_match_p (GLRO(dl_profile), l))
+ GL(dl_profile_map) = l;
+ }
+ else
+ {
+ rfunc = (ElfW(Addr)) &_dl_runtime_resolve;
+ }
+
+#if !defined __tilegx__
+ *plt++ = (0x400183aea0000fdcLL
+ | create_Imm16_X0 ((unsigned long) (l)));
+ *plt++ = (0x500000003000071cLL
+ | create_Imm16_X0 (((unsigned long) (l) + 0x8000) >> 16)
+ | create_JOffLong_X1 ((rfunc - (Elf32_Addr) &plt_base[1]) >> 3));
+#elif __WORDSIZE == 32
+ *plt++ = (0x000007ed90000fdcLL
+ | create_Imm16_X0 ((int) ((unsigned long) l >> 16))
+ | create_Imm16_X1 ((int) (rfunc >> 16)));
+ *plt++ = (0x3800036df000071cLL
+ | create_Imm16_X0 ((int) (unsigned long) l)
+ | create_Imm16_X1 ((int) rfunc));
+ *plt++ = 0x286a73604030afffLL;
+#else
+ *plt++ = (0x000007ed90000fdcLL
+ | create_Imm16_X0 ((int) ((unsigned long) l >> 32))
+ | create_Imm16_X1 ((int) (rfunc >> 32)));
+ *plt++ = (0x3800036df000071cLL
+ | create_Imm16_X0 ((int) ((unsigned long) l >> 16))
+ | create_Imm16_X1 ((int) (rfunc >> 16)));
+ *plt++ = (0x3800036df000071cLL
+ | create_Imm16_X0 ((int) (unsigned long) l)
+ | create_Imm16_X1 ((int) rfunc));
+ *plt++ = 0x286a73604030afffLL;
+#endif
+
+ _dl_flush_icache (plt_base, (char *) plt - (char *) plt_base);
+
+ return lazy;
+}
+
+/* In the old model, pltgot points to the .plt, which is initally 0,
+ then part of a trampoline after elf_machine_runtime_setup(). In
+ the new model, pltgot points to .got.plt, whose first entry is
+ initially -1, and the address of the struct link_map after
+ elf_machine_runtime_setup (). So we can test for which model of
+ plt we're running by examining the contents of pltgot. */
+static inline bool
+tile_old_plt_model (struct link_map *l, ElfW(Addr) *pltgot)
+{
+ return *pltgot != (ElfW(Addr)) l && *pltgot != (ElfW(Addr)) -1;
+}
+
+/* Set up the loaded object described by L so its unrelocated PLT
+ entries will jump to the on-demand fixup code in dl-runtime.c. */
+
+static inline int __attribute__ ((unused))
+elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+{
+ ElfW(Addr) *gotplt;
+ extern void _dl_runtime_resolve (ElfW(Word));
+ extern void _dl_runtime_profile (ElfW(Word));
+
+ if (l->l_info[DT_JMPREL] && lazy)
+ {
+ gotplt = (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
+
+ if (__builtin_expect (*gotplt != (ElfW(Addr)) -1, 0))
+ return old_elf_machine_runtime_setup (l, lazy, profile);
+
+ /* The GOT entries for functions in the PLT have not yet been filled
+ in. Their initial contents will arrange when called to put in
+ registers an offset into the .rel.plt section, and gotplt[0], then
+ jump to gotplt[1]. */
+
+ /* Identify this shared object. */
+ gotplt[0] = (ElfW(Addr)) l;
+
+ /* The gotplt[1] entry contains the address of a function which gets
+ called to get the address of a so far unresolved function and jump
+ to it. The profiling extension of the dynamic linker allows to
+ intercept the calls to collect information. In this case we don't
+ store the address in the GOTPLT so that all future calls also end
+ in this function. */
+ if (__builtin_expect (profile, 0))
+ {
+ gotplt[1] = (ElfW(Addr)) &_dl_runtime_profile;
+
+ if (GLRO(dl_profile) != NULL
+ && _dl_name_match_p (GLRO(dl_profile), l))
+ /* This is the object we are looking for. Say that we really
+ want profiling and the timers are started. */
+ GL(dl_profile_map) = l;
+ }
+ else
+ /* This function will get called to fix up the GOTPLT entry
+ indicated by the offset on the stack, and then jump to the
+ resolved address. */
+ gotplt[1] = (ElfW(Addr)) &_dl_runtime_resolve;
+ }
+
+ return lazy;
+}
+
+#if __WORDSIZE == 32
+/* Mask identifying addresses reserved for the user program,
+ where the dynamic linker should not map anything. */
+#define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL
+#endif
+
+/* Initial entry point code for the dynamic linker.
+ The C function `_dl_start' is the real entry point;
+ its return value is the user program's entry point. */
+
+#define RTLD_START asm (".globl _dl_start");
+
+#ifndef RTLD_START_SPECIAL_INIT
+#define RTLD_START_SPECIAL_INIT /* nothing */
+#endif
+
+/* Wrap a generic Tilera relocation type. */
+#ifdef __tilegx__
+#define R_TILE(x) R_TILEGX_##x
+#define __R_TILE_TLS(x,c) R_TILEGX_TLS_##x##c
+#define _R_TILE_TLS(x,c) __R_TILE_TLS(x,c)
+#define R_TILE_TLS(x) _R_TILE_TLS(x,__ELF_NATIVE_CLASS)
+#else
+#define R_TILE(x) R_TILEPRO_##x
+#define R_TILE_TLS(x) R_TILEPRO_TLS_##x##32
+#endif
+
+/* 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_TILE(JMP_SLOT) || (type) == R_TILE_TLS(DTPMOD) \
+ || (type) == R_TILE_TLS(DTPOFF) || (type) == R_TILE_TLS(TPOFF)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_TILE(COPY)) * ELF_RTYPE_CLASS_COPY))
+
+/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
+#define ELF_MACHINE_JMP_SLOT R_TILE(JMP_SLOT)
+
+/* TILE never uses Elf32_Rel relocations. */
+#define ELF_MACHINE_NO_REL 1
+
+/* TILE overlaps DT_RELA and DT_PLTREL. */
+#define ELF_MACHINE_PLTREL_OVERLAP 1
+
+/* We define an initialization functions. This is called very early in
+ _dl_sysdep_start. */
+#define DL_PLATFORM_INIT dl_platform_init ()
+
+static inline void __attribute__ ((unused))
+dl_platform_init (void)
+{
+ if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
+ /* Avoid an empty string which would disturb us. */
+ GLRO(dl_platform) = NULL;
+}
+
+static inline ElfW(Addr)
+old_elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+ const ElfW(Rela) *reloc,
+ ElfW(Addr) *reloc_addr, ElfW(Addr) value)
+{
+#ifndef __tilegx__
+ /* Updating a PLT entry atomically on TILEPro is very tricky, since
+ bundles are 8 bytes, we can only atomically write four bytes at a
+ time, and jump instructions span both words of the bundle.
+
+ We carefully update one word and then the other in an order
+ such that the intermediate values seen by any reader are
+ all valid code sequences. It is fortuitous that such a sequence
+ exists.
+
+ Initially each PLT entry looks like this:
+
+ { auli r29, zero, MY_PLT_INDEX ; bzt zero, _PROCEDURE_LINKAGE_TABLE_ }
+
+ Our goal is to change the 'bzt' into 'j target'.
+
+ First we modify the low word to change just the part of the 'j' offset
+ that "spills over" into the low word of the bundle. This turns out
+ to only be one bit. Fortuitously this bit is the same bit that
+ distinguishes 'bzt' from 'bz'. So the above bundle either stays the
+ same or the 'bzt' changes to 'bz'. So temporarily we have one of
+ these bundles:
+
+ { auli r29, zero, MY_PLT_INDEX ; bz zero, _PROCEDURE_LINKAGE_TABLE_ }
+ { auli r29, zero, MY_PLT_INDEX ; bzt zero, _PROCEDURE_LINKAGE_TABLE_ }
+
+ These are semantically identical, so if some other thread executes
+ this bundle partway through its being updated, nothing bad happens.
+
+ Finally we write the second word of the bundle, which includes the
+ 'j' opcode and all but one of the jump offset bits. That yields
+ the final result:
+
+ { auli r29, zero, MY_PLT_INDEX ; j target }
+
+ The auli is now unnecessary but we don't bother replacing it with a fnop
+ (although we could). */
+
+ long offset = (const char *) value - (const char *) reloc_addr;
+ tile_bundle_bits new_bundle =
+ (((0x5000000000000000LL | ((unsigned long *) reloc_addr)[0])
+ & ~create_JOffLong_X1 (-1))
+ | create_JOffLong_X1 (offset >> 3));
+
+ /* Write out the low word. The only thing we are changing here from
+ the default entry is one bit of jump offset, which might change
+ the bzt into a bz, but that's harmless. */
+ ((volatile unsigned long *) reloc_addr)[0] = (unsigned long) new_bundle;
+
+ /* Guarantee that the first store is definitely visible before the
+ second store in case some other thread starts executing this PLT
+ entry right now. This may be unnecessary since the stores should
+ be ordered, but there's little cost to paranoia here. */
+ __insn_mf ();
+
+ /* Now change the bzt/bz into a j, and set the remaining jump offset
+ bits (which are stored in this word). */
+ ((volatile unsigned long *) reloc_addr)[1] =
+ (unsigned long) (new_bundle >> 32);
+
+ _dl_flush_icache (reloc_addr, sizeof (tile_bundle_bits));
+#else
+ /* Updating a PLT entry on TILE-Gx is easier, since we can write an
+ 8-byte instruction in a single instruction. Initially each PLT
+ entry looks like this:
+
+ { shl16insli r29, zero, MY_PLT_INDEX ; j _PROCEDURE_LINKAGE_TABLE_ }
+ { jr r29 }
+ { jr r29 }
+ { jr r29 }
+
+ Our goal is to change this into a jump to 'target'.
+
+ If 'target' is within the relative offset of a 'j' instruction,
+ we just use that, for efficiency. Otherwise we spend up to three
+ bundles materializing the address in r29 and then 'jr r29'. */
+
+ /* Even in 32-bit mode the PC is actually 64 bits, so we cannot rely
+ on it "wrapping around". So we always check for jump distance
+ using the offset as 64-bit pointers. We right shift by 3 because
+ jump offsets are always in terms of bundles. */
+ long long offset =
+ ((long long) (intptr_t) value -
+ ((long long) (intptr_t) reloc_addr)) >> 3;
+
+ /* WARNING: Other threads may be modifying or executing the code
+ we are self-modifying, so we need to be very careful about the
+ order in which we self-modify. */
+ tile_bundle_bits *bundles = (tile_bundle_bits *) reloc_addr;
+ tile_bundle_bits first_bundle;
+
+ /* Determine size of jump offset. */
+ int shift = __builtin_clzll (get_JumpOff_X1 (create_JumpOff_X1 (~0)));
+
+ /* Sign extend the jump offset we stored into the bundle, so
+ we can see if any information was lost via overflow. */
+ long long f = get_JumpOff_X1 (create_JumpOff_X1 (offset));
+ f = (f << shift) >> shift;
+
+ if (offset == f)
+ {
+ /* { j value } */
+ first_bundle = 0x2400000051483000ULL | create_JumpOff_X1 (offset);
+ }
+ else
+ {
+ ElfW(Addr) t = (unsigned long) value;
+
+#if __SIZEOF_POINTER__ == 4
+ /* { moveli r29, hw1_last(value) } */
+ first_bundle = 0x000007eed1483000ULL | create_Imm16_X1 (t >> 16);
+
+ /* { shl16insli r29, r29, hw0(value) } */
+ bundles[1] = 0x380003aed1483000ULL | create_Imm16_X1 (t);
+#else
+ /* { moveli r29, hw2_last(value) } */
+ first_bundle = 0x000007eed1483000ULL | create_Imm16_X1 (t >> 32);
+
+ /* { shl16insli r29, r29, hw1(value) } */
+ bundles[1] = 0x380003aed1483000ULL | create_Imm16_X1 (t >> 16);
+
+ /* { shl16insli r29, r29, hw0(value) } */
+ bundles[2] = 0x380003aed1483000ULL | create_Imm16_X1 (t);
+#endif
+
+ /* Make sure that every other thread can see the preceding
+ bundles before we modify the first one and make them visible. */
+ _dl_flush_icache (&bundles[1], 2 * sizeof (bundles[0]));
+ }
+
+ /* Finally, record the first bundle. */
+ bundles[0] = first_bundle;
+ _dl_flush_icache (&bundles[0], sizeof (bundles[0]));
+#endif
+
+ return value;
+}
+
+static inline ElfW(Addr)
+elf_machine_fixup_plt (struct link_map *map, lookup_t t,
+ const ElfW(Rela) *reloc,
+ ElfW(Addr) *reloc_addr, ElfW(Addr) value)
+{
+ ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
+
+ if (__builtin_expect (tile_old_plt_model (map, gotplt), 0))
+ return old_elf_machine_fixup_plt (map, t, reloc, reloc_addr, value);
+
+ return *reloc_addr = value;
+}
+
+/* Return the final value of a plt relocation. */
+static inline ElfW(Addr)
+elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
+ ElfW(Addr) value)
+{
+ return value;
+}
+
+/* Support notifying the simulator about new objects. */
+void internal_function _dl_arch_map_object (struct link_map *l);
+#define _dl_arch_map_object _dl_arch_map_object
+
+/* Names of the architecture-specific auditing callback functions. */
+#define ARCH_LA_PLTENTER tile_gnu_pltenter
+#define ARCH_LA_PLTEXIT tile_gnu_pltexit
+
+#endif /* !dl_machine_h */
+
+
+#ifdef RESOLVE_MAP
+
+struct reloc_howto
+{
+ /* Right shift operand by this number of bits. */
+ unsigned char right_shift;
+
+#ifdef __tilegx__
+ /* If nonzero, this is updating a code bundle. */
+ unsigned char is_bundle_update;
+#else
+ /* If nonzero, add 0x8000 to the value. */
+ unsigned char add_0x8000;
+#endif
+
+ /* If nonzero, subtract the containing address from the address. */
+ unsigned char is_pcrel;
+
+ /* Size in bytes, or 0 if this table entry should be ignored. */
+ unsigned char byte_size;
+};
+
+/* Relocation information. Cannot contain create_* function pointers
+ because then the table would not be position-independent. */
+static const struct reloc_howto howto[] =
+{
+#ifdef __tilegx__
+
+# if __WORDSIZE == 32
+ /* The GX -m32 loader only handles 32-bit types, so it will be confused
+ by shifts larger than that. We convert them to just sign-extend;
+ they usually indicate a program bug or missed optimization, but we
+ have to handle them correctly anyway. */
+# define S32 31
+# define S48 31
+# else
+# define S32 32
+# define S48 48
+# endif
+
+ /* R_TILEGX_NONE */ { 0, 0, 0, 0 },
+ /* R_TILEGX_64 */ { 0, 0, 0, 8 },
+ /* R_TILEGX_32 */ { 0, 0, 0, 4 },
+ /* R_TILEGX_16 */ { 0, 0, 0, 2 },
+ /* R_TILEGX_8 */ { 0, 0, 0, 1 },
+ /* R_TILEGX_64_PCREL */ { 0, 0, 1, 8 },
+ /* R_TILEGX_32_PCREL */ { 0, 0, 1, 4 },
+ /* R_TILEGX_16_PCREL */ { 0, 0, 1, 2 },
+ /* R_TILEGX_8_PCREL */ { 0, 0, 1, 1 },
+ /* R_TILEGX_HW0 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_HW1 */ { 16, 0, 0, 0 },
+ /* R_TILEGX_HW2 */ { S32, 0, 0, 0 },
+ /* R_TILEGX_HW3 */ { S48, 0, 0, 0 },
+ /* R_TILEGX_HW0_LAST */ { 0, 0, 0, 0 },
+ /* R_TILEGX_HW1_LAST */ { 16, 0, 0, 0 },
+ /* R_TILEGX_HW2_LAST */ { S32, 0, 0, 0 },
+ /* R_TILEGX_COPY */ { 0, 0, 0, 0 },
+ /* R_TILEGX_GLOB_DAT */ { 0, 0, 0, 8 },
+ /* R_TILEGX_JMP_SLOT */ { 0, 0, 0, 0 },
+ /* R_TILEGX_RELATIVE */ { 0, 0, 0, 0 },
+ /* R_TILEGX_BROFF_X1 */ { 3, 1, 1, 8 },
+ /* R_TILEGX_JUMPOFF_X1 */ { 3, 1, 1, 8 },
+ /* R_TILEGX_JUMPOFF_X1_PLT */ { 3, 1, 1, 8 },
+ /* R_TILEGX_IMM8_X0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM8_Y0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM8_X1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM8_Y1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_DEST_IMM8_X1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_MT_IMM14_X1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_MF_IMM14_X1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_MMSTART_X0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_MMEND_X0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_SHAMT_X0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_SHAMT_X1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_SHAMT_Y0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_SHAMT_Y1 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0 */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1 */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1 */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2 */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2 */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW3 */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW3 */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_LAST */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_LAST */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_LAST */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_LAST */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_LAST */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_LAST */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_PCREL */ { 0, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_PCREL */ { 0, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_PCREL */ { S32, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_PCREL */ { S32, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW3_PCREL */ { S48, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW3_PCREL */ { S48, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_LAST_PCREL */ { 0, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_LAST_PCREL */ { 0, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_LAST_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_LAST_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_LAST_PCREL */ { S32, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_LAST_PCREL */ { S32, 1, 1, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_GOT */ { 0, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW0_GOT */ { 0, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW1_GOT */ { 16, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW1_GOT */ { 16, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW2_GOT */ { S32, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW2_GOT */ { S32, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW3_GOT */ { S48, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW3_GOT */ { S48, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW0_LAST_GOT */ { 0, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW0_LAST_GOT */ { 0, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW1_LAST_GOT */ { 16, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW1_LAST_GOT */ { 16, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW2_LAST_GOT */ { S32, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X1_HW2_LAST_GOT */ { S32, 1, 0, 0 },
+ /* R_TILEGX_IMM16_X0_HW0_TLS_GD */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_TLS_GD */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_TLS_GD */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_TLS_GD */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_TLS_GD */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_TLS_GD */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW3_TLS_GD */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW3_TLS_GD */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD */{ 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD */{ 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD */{ 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD */{ 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD */{ S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD */{ S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_TLS_IE */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_TLS_IE */ { 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_TLS_IE */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_TLS_IE */ { 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_TLS_IE */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_TLS_IE */ { S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW3_TLS_IE */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW3_TLS_IE */ { S48, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE */{ 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE */{ 0, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE */{ 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE */{ 16, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE */{ S32, 1, 0, 8 },
+ /* R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE */{ S32, 1, 0, 8 },
+ /* R_TILEGX_TLS_DTPMOD64 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_TLS_DTPOFF64 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_TLS_TPOFF64 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_TLS_DTPMOD32 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_TLS_DTPOFF32 */ { 0, 0, 0, 0 },
+ /* R_TILEGX_TLS_TPOFF32 */ { 0, 0, 0, 0 }
+#else
+ /* R_TILEPRO_NONE */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_32 */ { 0, 0, 0, 4 },
+ /* R_TILEPRO_16 */ { 0, 0, 0, 2 },
+ /* R_TILEPRO_8 */ { 0, 0, 0, 1 },
+ /* R_TILEPRO_32_PCREL */ { 0, 0, 1, 4 },
+ /* R_TILEPRO_16_PCREL */ { 0, 0, 1, 2 },
+ /* R_TILEPRO_8_PCREL */ { 0, 0, 1, 1 },
+ /* R_TILEPRO_LO16 */ { 0, 0, 0, 2 },
+ /* R_TILEPRO_HI16 */ { 16, 0, 0, 2 },
+ /* R_TILEPRO_HA16 */ { 16, 1, 0, 2 },
+ /* R_TILEPRO_COPY */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_GLOB_DAT */ { 0, 0, 0, 4 },
+ /* R_TILEPRO_JMP_SLOT */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_RELATIVE */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_BROFF_X1 */ { 3, 0, 1, 8 },
+ /* R_TILEPRO_JOFFLONG_X1 */ { 3, 0, 1, 8 },
+ /* R_TILEPRO_JOFFLONG_X1_PLT */ { 3, 0, 1, 8 },
+ /* R_TILEPRO_IMM8_X0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM8_Y0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM8_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM8_Y1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_MT_IMM15_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_MF_IMM15_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_PCREL */ { 0, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X1_PCREL */ { 0, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X0_LO_PCREL */ { 0, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X1_LO_PCREL */ { 0, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X0_HI_PCREL */ { 16, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X1_HI_PCREL */ { 16, 0, 1, 8 },
+ /* R_TILEPRO_IMM16_X0_HA_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEPRO_IMM16_X1_HA_PCREL */ { 16, 1, 1, 8 },
+ /* R_TILEPRO_IMM16_X0_GOT */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X1_GOT */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X0_GOT_LO */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X1_GOT_LO */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X0_GOT_HI */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X1_GOT_HI */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X0_GOT_HA */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X1_GOT_HA */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_MMSTART_X0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_MMEND_X0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_MMSTART_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_MMEND_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_SHAMT_X0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_SHAMT_X1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_SHAMT_Y0 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_SHAMT_Y1 */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_SN_BROFF */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_IMM8 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_UIMM8 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_BYTE0 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_BYTE1 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_BYTE2 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_BYTE3 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_SPCREL0 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_SPCREL1 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_SPCREL2 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_SN_SPCREL3 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_IMM16_X0_TLS_GD */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_GD */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_GD_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_GD_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_GD_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_GD_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_GD_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_GD_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_IE */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_IE */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_IE_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_IE_LO */ { 0, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_IE_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_IE_HI */ { 16, 0, 0, 8 },
+ /* R_TILEPRO_IMM16_X0_TLS_IE_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_IMM16_X1_TLS_IE_HA */ { 16, 1, 0, 8 },
+ /* R_TILEPRO_TLS_DTPMOD32 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_TLS_DTPOFF32 */ { 0, 0, 0, 0 },
+ /* R_TILEPRO_TLS_TPOFF32 */ { 0, 0, 0, 0 },
+#endif
+};
+
+#if __ELF_NATIVE_CLASS == 32
+#define ELFW_R_TYPE ELF32_R_TYPE
+#define ELFW_ST_TYPE ELF32_ST_TYPE
+#else
+#define ELFW_R_TYPE ELF64_R_TYPE
+#define ELFW_ST_TYPE ELF64_ST_TYPE
+#endif
+
+/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
+ MAP is the object containing the reloc. */
+
+auto inline void __attribute__ ((always_inline))
+elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
+ const ElfW(Sym) *sym, const struct r_found_version *version,
+ void *const reloc_addr_arg, int skip_ifunc)
+{
+ ElfW(Addr) *const reloc_addr = reloc_addr_arg;
+ const unsigned int r_type = ELFW_R_TYPE (reloc->r_info);
+
+#if !defined RTLD_BOOTSTRAP || !defined HAVE_Z_COMBRELOC
+ if (__builtin_expect (r_type == R_TILE(RELATIVE), 0))
+ {
+# if !defined RTLD_BOOTSTRAP && !defined HAVE_Z_COMBRELOC
+ /* This is defined in rtld.c, but nowhere in the static libc.a;
+ make the reference weak so static programs can still link.
+ This declaration cannot be done when compiling rtld.c
+ (i.e. #ifdef RTLD_BOOTSTRAP) because rtld.c contains the
+ common defn for _dl_rtld_map, which is incompatible with a
+ weak decl in the same file. */
+# ifndef SHARED
+ weak_extern (GL(dl_rtld_map));
+# endif
+ if (map != &GL(dl_rtld_map)) /* Already done in rtld itself. */
+# endif
+ *reloc_addr = map->l_addr + reloc->r_addend;
+ return;
+ }
+#endif
+
+ if (__builtin_expect (r_type == R_TILE(NONE), 0))
+ return;
+
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
+ const ElfW(Sym) *const refsym = sym;
+#endif
+ struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
+ ElfW(Addr) value;
+
+ if (sym == NULL)
+ value = 0;
+ else if (ELFW_ST_TYPE (sym->st_info) == STT_SECTION)
+ value = map->l_addr; /* like a RELATIVE reloc */
+ else
+ value = sym_map->l_addr + sym->st_value;
+
+ if (sym != NULL
+ && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)
+ && __builtin_expect (sym->st_shndx != SHN_UNDEF, 1)
+ && __builtin_expect (!skip_ifunc, 1))
+ value = ((Elf64_Addr (*) (void)) value) ();
+
+ switch (r_type)
+ {
+ case R_TILE(JMP_SLOT):
+ elf_machine_fixup_plt (map, 0, reloc, reloc_addr,
+ value + reloc->r_addend);
+ return;
+
+#ifndef RESOLVE_CONFLICT_FIND_MAP
+ case R_TILE_TLS(DTPMOD):
+# ifdef RTLD_BOOTSTRAP
+ /* During startup the dynamic linker is always the module
+ with index 1.
+ XXX If this relocation is necessary move before RESOLVE
+ call. */
+ *reloc_addr = 1;
+# else
+ /* Get the information from the link map returned by the
+ resolv function. */
+ if (sym_map != NULL)
+ *reloc_addr = sym_map->l_tls_modid;
+# endif
+ return;
+ case R_TILE_TLS(DTPOFF):
+# ifndef RTLD_BOOTSTRAP
+ /* During relocation all TLS symbols are defined and used.
+ Therefore the offset is already correct. */
+ if (sym != NULL)
+ *reloc_addr = sym->st_value + reloc->r_addend;
+# endif
+ return;
+ case R_TILE_TLS(TPOFF):
+# ifdef RTLD_BOOTSTRAP
+ *reloc_addr = sym->st_value + reloc->r_addend + map->l_tls_offset;
+# else
+ if (sym != NULL)
+ {
+ CHECK_STATIC_TLS (map, sym_map);
+ *reloc_addr = (sym->st_value + reloc->r_addend
+ + sym_map->l_tls_offset);
+ }
+#endif
+ return;
+#endif /* use TLS */
+
+#if !defined RTLD_BOOTSTRAP && !defined RESOLVE_CONFLICT_FIND_MAP
+ /* Not needed in dl-conflict.c. */
+ case R_TILE(COPY):
+ if (sym == NULL)
+ /* This can happen in trace mode if an object could not be found. */
+ return;
+ if (__builtin_expect (sym->st_size > refsym->st_size, 0)
+ || (__builtin_expect (sym->st_size < refsym->st_size, 0)
+ && __builtin_expect (GLRO(dl_verbose), 0)))
+ {
+ const char *strtab;
+
+ strtab = (const char *) D_PTR (map,l_info[DT_STRTAB]);
+ _dl_error_printf ("%s: Symbol `%s' has different size in shared"
+ " object, consider re-linking\n",
+ rtld_progname ?: "<program name unknown>",
+ strtab + refsym->st_name);
+ }
+ memcpy (reloc_addr_arg, (void *) value,
+ MIN (sym->st_size, refsym->st_size));
+ return;
+#endif
+ }
+
+ /* All remaining relocations must be in the lookup table. */
+ const struct reloc_howto *h = &howto[r_type];
+ if ((unsigned int) r_type >= sizeof howto / sizeof howto[0] ||
+ h->byte_size == 0)
+ {
+#if !defined RTLD_BOOTSTRAP || defined _NDEBUG
+ /* We add these checks in the version to relocate ld.so only
+ if we are still debugging. */
+ _dl_reloc_bad_type (map, r_type, 0);
+#endif
+ return;
+ }
+
+ value += reloc->r_addend;
+
+ /* The lookup table entry knows how to perform this reloc. */
+ if (h->is_pcrel)
+ value -= (ElfW(Addr)) reloc_addr;
+
+#ifndef __tilegx__
+ if (h->add_0x8000)
+ value += 0x8000;
+#endif
+
+ value >>= h->right_shift;
+
+ switch (h->byte_size)
+ {
+ case 1:
+ *(char *) reloc_addr = value;
+ return;
+ case 2:
+ *(short *) reloc_addr = value;
+ return;
+ case 4:
+ *(int *) reloc_addr = value;
+ return;
+#ifdef __tilegx__
+ case 8:
+ if (!h->is_bundle_update)
+ {
+ *(ElfW(Addr) *) reloc_addr = value;
+ return;
+ }
+#endif
+ }
+
+ /* We are updating a bundle, so use the function pointer that
+ swizzles the operand bits into the right location. */
+
+ tile_bundle_bits *p = (tile_bundle_bits *) reloc_addr;
+ tile_bundle_bits bits = *p;
+
+#define MUNGE(func) do { \
+ bits = ((bits & ~create_##func (-1)) | create_##func (value)); \
+ if (get_##func (bits) != value) \
+ _dl_signal_error (0, map->l_name, NULL, \
+ "relocation value too large for " #func); \
+ } while (0)
+
+#define MUNGE_NOCHECK(func) \
+ bits = ((bits & ~create_##func (-1)) | create_##func (value))
+
+ switch (r_type)
+ {
+#ifdef __tilegx__
+ case R_TILEGX_BROFF_X1:
+ MUNGE (BrOff_X1);
+ break;
+ case R_TILEGX_JUMPOFF_X1:
+ case R_TILEGX_JUMPOFF_X1_PLT:
+ MUNGE (JumpOff_X1);
+ break;
+ case R_TILEGX_IMM8_X0:
+ MUNGE (Imm8_X0);
+ break;
+ case R_TILEGX_IMM8_Y0:
+ MUNGE (Imm8_Y0);
+ break;
+ case R_TILEGX_IMM8_X1:
+ MUNGE (Imm8_X1);
+ break;
+ case R_TILEGX_IMM8_Y1:
+ MUNGE (Imm8_Y1);
+ break;
+ case R_TILEGX_MT_IMM14_X1:
+ MUNGE (MT_Imm14_X1);
+ break;
+ case R_TILEGX_MF_IMM14_X1:
+ MUNGE (MF_Imm14_X1);
+ break;
+ case R_TILEGX_IMM16_X0_HW0:
+ case R_TILEGX_IMM16_X0_HW1:
+ case R_TILEGX_IMM16_X0_HW2:
+ case R_TILEGX_IMM16_X0_HW3:
+ case R_TILEGX_IMM16_X0_HW0_PCREL:
+ case R_TILEGX_IMM16_X0_HW1_PCREL:
+ case R_TILEGX_IMM16_X0_HW2_PCREL:
+ case R_TILEGX_IMM16_X0_HW3_PCREL:
+ case R_TILEGX_IMM16_X0_HW0_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW1_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW2_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW3_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW0_TLS_IE:
+ case R_TILEGX_IMM16_X0_HW1_TLS_IE:
+ case R_TILEGX_IMM16_X0_HW2_TLS_IE:
+ case R_TILEGX_IMM16_X0_HW3_TLS_IE:
+ MUNGE_NOCHECK (Imm16_X0);
+ break;
+ case R_TILEGX_IMM16_X0_HW0_LAST:
+ case R_TILEGX_IMM16_X0_HW1_LAST:
+ case R_TILEGX_IMM16_X0_HW2_LAST:
+ case R_TILEGX_IMM16_X0_HW0_LAST_PCREL:
+ case R_TILEGX_IMM16_X0_HW1_LAST_PCREL:
+ case R_TILEGX_IMM16_X0_HW2_LAST_PCREL:
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW2_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE:
+ case R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE:
+ case R_TILEGX_IMM16_X0_HW2_LAST_TLS_IE:
+ MUNGE (Imm16_X0);
+ break;
+ case R_TILEGX_IMM16_X1_HW0:
+ case R_TILEGX_IMM16_X1_HW1:
+ case R_TILEGX_IMM16_X1_HW2:
+ case R_TILEGX_IMM16_X1_HW3:
+ case R_TILEGX_IMM16_X1_HW0_PCREL:
+ case R_TILEGX_IMM16_X1_HW1_PCREL:
+ case R_TILEGX_IMM16_X1_HW2_PCREL:
+ case R_TILEGX_IMM16_X1_HW3_PCREL:
+ case R_TILEGX_IMM16_X1_HW0_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW1_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW2_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW3_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW0_TLS_IE:
+ case R_TILEGX_IMM16_X1_HW1_TLS_IE:
+ case R_TILEGX_IMM16_X1_HW2_TLS_IE:
+ case R_TILEGX_IMM16_X1_HW3_TLS_IE:
+ MUNGE_NOCHECK (Imm16_X1);
+ break;
+ case R_TILEGX_IMM16_X1_HW0_LAST:
+ case R_TILEGX_IMM16_X1_HW1_LAST:
+ case R_TILEGX_IMM16_X1_HW2_LAST:
+ case R_TILEGX_IMM16_X1_HW0_LAST_PCREL:
+ case R_TILEGX_IMM16_X1_HW1_LAST_PCREL:
+ case R_TILEGX_IMM16_X1_HW2_LAST_PCREL:
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW2_LAST_TLS_GD:
+ case R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE:
+ case R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE:
+ case R_TILEGX_IMM16_X1_HW2_LAST_TLS_IE:
+ MUNGE (Imm16_X1);
+ break;
+ case R_TILEGX_MMSTART_X0:
+ MUNGE (BFStart_X0);
+ break;
+ case R_TILEGX_MMEND_X0:
+ MUNGE (BFEnd_X0);
+ break;
+ case R_TILEGX_SHAMT_X0:
+ MUNGE (ShAmt_X0);
+ break;
+ case R_TILEGX_SHAMT_X1:
+ MUNGE (ShAmt_X1);
+ break;
+ case R_TILEGX_SHAMT_Y0:
+ MUNGE (ShAmt_Y0);
+ break;
+ case R_TILEGX_SHAMT_Y1:
+ MUNGE (ShAmt_Y1);
+ break;
+#else
+ case R_TILEPRO_BROFF_X1:
+ MUNGE (BrOff_X1);
+ break;
+ case R_TILEPRO_JOFFLONG_X1:
+ case R_TILEPRO_JOFFLONG_X1_PLT:
+ MUNGE_NOCHECK (JOffLong_X1); /* holds full 32-bit value */
+ break;
+ case R_TILEPRO_IMM8_X0:
+ MUNGE (Imm8_X0);
+ break;
+ case R_TILEPRO_IMM8_Y0:
+ MUNGE (Imm8_Y0);
+ break;
+ case R_TILEPRO_IMM8_X1:
+ MUNGE (Imm8_X1);
+ break;
+ case R_TILEPRO_IMM8_Y1:
+ MUNGE (Imm8_Y1);
+ break;
+ case R_TILEPRO_MT_IMM15_X1:
+ MUNGE (MT_Imm15_X1);
+ break;
+ case R_TILEPRO_MF_IMM15_X1:
+ MUNGE (MF_Imm15_X1);
+ break;
+ case R_TILEPRO_IMM16_X0_LO:
+ case R_TILEPRO_IMM16_X0_HI:
+ case R_TILEPRO_IMM16_X0_HA:
+ case R_TILEPRO_IMM16_X0_LO_PCREL:
+ case R_TILEPRO_IMM16_X0_HI_PCREL:
+ case R_TILEPRO_IMM16_X0_HA_PCREL:
+ case R_TILEPRO_IMM16_X0_TLS_GD_LO:
+ case R_TILEPRO_IMM16_X0_TLS_GD_HI:
+ case R_TILEPRO_IMM16_X0_TLS_GD_HA:
+ case R_TILEPRO_IMM16_X0_TLS_IE_LO:
+ case R_TILEPRO_IMM16_X0_TLS_IE_HI:
+ case R_TILEPRO_IMM16_X0_TLS_IE_HA:
+ MUNGE_NOCHECK (Imm16_X0);
+ break;
+ case R_TILEPRO_IMM16_X0:
+ case R_TILEPRO_IMM16_X0_PCREL:
+ case R_TILEPRO_IMM16_X0_TLS_GD:
+ case R_TILEPRO_IMM16_X0_TLS_IE:
+ MUNGE (Imm16_X0);
+ break;
+ case R_TILEPRO_IMM16_X1_LO:
+ case R_TILEPRO_IMM16_X1_HI:
+ case R_TILEPRO_IMM16_X1_HA:
+ case R_TILEPRO_IMM16_X1_LO_PCREL:
+ case R_TILEPRO_IMM16_X1_HI_PCREL:
+ case R_TILEPRO_IMM16_X1_HA_PCREL:
+ case R_TILEPRO_IMM16_X1_TLS_GD_LO:
+ case R_TILEPRO_IMM16_X1_TLS_GD_HI:
+ case R_TILEPRO_IMM16_X1_TLS_GD_HA:
+ case R_TILEPRO_IMM16_X1_TLS_IE_LO:
+ case R_TILEPRO_IMM16_X1_TLS_IE_HI:
+ case R_TILEPRO_IMM16_X1_TLS_IE_HA:
+ MUNGE_NOCHECK (Imm16_X1);
+ break;
+ case R_TILEPRO_IMM16_X1:
+ case R_TILEPRO_IMM16_X1_PCREL:
+ case R_TILEPRO_IMM16_X1_TLS_GD:
+ case R_TILEPRO_IMM16_X1_TLS_IE:
+ MUNGE (Imm16_X1);
+ break;
+ case R_TILEPRO_MMSTART_X0:
+ MUNGE (MMStart_X0);
+ break;
+ case R_TILEPRO_MMEND_X0:
+ MUNGE (MMEnd_X0);
+ break;
+ case R_TILEPRO_MMSTART_X1:
+ MUNGE (MMStart_X1);
+ break;
+ case R_TILEPRO_MMEND_X1:
+ MUNGE (MMEnd_X1);
+ break;
+ case R_TILEPRO_SHAMT_X0:
+ MUNGE (ShAmt_X0);
+ break;
+ case R_TILEPRO_SHAMT_X1:
+ MUNGE (ShAmt_X1);
+ break;
+ case R_TILEPRO_SHAMT_Y0:
+ MUNGE (ShAmt_Y0);
+ break;
+ case R_TILEPRO_SHAMT_Y1:
+ MUNGE (ShAmt_Y1);
+ break;
+#endif
+ }
+#undef MUNGE
+ *p = bits;
+ _dl_flush_icache (p, sizeof (*p));
+}
+
+auto inline void __attribute__ ((always_inline))
+elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ void *const reloc_addr_arg)
+{
+ ElfW(Addr) *const reloc_addr = reloc_addr_arg;
+ *reloc_addr = l_addr + reloc->r_addend;
+}
+
+auto inline void __attribute__ ((always_inline))
+elf_machine_lazy_rel (struct link_map *map,
+ ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
+ int skip_ifunc)
+{
+ const unsigned int r_type = ELF32_R_TYPE (reloc->r_info);
+
+ /* Check for unexpected PLT reloc type. */
+ if (__builtin_expect (r_type == R_TILE(JMP_SLOT), 1))
+ {
+ ElfW(Addr) *gotplt = (ElfW(Addr) *) D_PTR (map, l_info[DT_PLTGOT]);
+
+ if (__builtin_expect (!tile_old_plt_model (map, gotplt), 1))
+ {
+ ElfW(Addr) *const reloc_addr = (void *) (l_addr + reloc->r_offset);
+ *reloc_addr += l_addr;
+ }
+ }
+ else
+ _dl_reloc_bad_type (map, r_type, 1);
+}
+
+#endif /* RESOLVE_MAP */
diff --git a/sysdeps/tile/dl-runtime.c b/sysdeps/tile/dl-runtime.c
new file mode 100644
index 0000000..e8a8361
--- /dev/null
+++ b/sysdeps/tile/dl-runtime.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Like x86_64, we pass the index of the relocation and not its offset.
+ In _dl_profile_fixup and _dl_call_pltexit we also use the index.
+ Therefore it is wasteful to compute the offset in the trampoline
+ just to reverse the operation immediately afterwards. */
+#define reloc_offset reloc_arg * sizeof (PLTREL)
+#define reloc_index reloc_arg
+
+#include <elf/dl-runtime.c>
+
+#include <sys/mman.h>
+#include <arch/sim.h>
+
+/* Support notifying the simulator about new objects. */
+void internal_function
+_dl_arch_map_object (struct link_map *l)
+{
+ int shift;
+
+#define DLPUTC(c) __insn_mtspr(SPR_SIM_CONTROL, \
+ (SIM_CONTROL_DLOPEN \
+ | ((c) << _SIM_CONTROL_OPERATOR_BITS)))
+
+ /* Write the library address in hex. */
+ DLPUTC ('0');
+ DLPUTC ('x');
+ for (shift = (int) sizeof (unsigned long) * 8 - 4; shift >= 0; shift -= 4)
+ DLPUTC ("0123456789abcdef"[(l->l_map_start >> shift) & 0xF]);
+ DLPUTC (':');
+
+ /* Write the library path, including the terminating '\0'. */
+ for (size_t i = 0;; i++)
+ {
+ DLPUTC (l->l_name[i]);
+ if (l->l_name[i] == '\0')
+ break;
+ }
+#undef DLPUTC
+}
+
+/* Support notifying the simulator about removed objects prior to munmap(). */
+void internal_function
+_dl_unmap (struct link_map *l)
+{
+ int shift;
+
+#define DLPUTC(c) __insn_mtspr(SPR_SIM_CONTROL, \
+ (SIM_CONTROL_DLCLOSE \
+ | ((c) << _SIM_CONTROL_OPERATOR_BITS)))
+
+ /* Write the library address in hex. */
+ DLPUTC ('0');
+ DLPUTC ('x');
+ for (shift = (int) sizeof (unsigned long) * 8 - 4; shift >= 0; shift -= 4)
+ DLPUTC ("0123456789abcdef"[(l->l_map_start >> shift) & 0xF]);
+ DLPUTC ('\0');
+#undef DLPUTC
+
+ __munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start);
+}
+
+#define DL_UNMAP(map) _dl_unmap (map)
diff --git a/sysdeps/tile/dl-start.S b/sysdeps/tile/dl-start.S
new file mode 100644
index 0000000..2991374
--- /dev/null
+++ b/sysdeps/tile/dl-start.S
@@ -0,0 +1,114 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+
+ /* Get address of "sym" in "reg" assuming r51 holds ".Llink". */
+ .macro pic_addr reg, sym
+#ifdef __tilegx__
+ moveli \reg, hw1_last(\sym - .Llink)
+ shl16insli \reg, \reg, hw0(\sym - .Llink)
+ ADD_PTR \reg, r51, \reg
+#else
+ ADDLI_PTR \reg, r51, lo16(\sym - .Llink)
+ auli \reg, \reg, ha16(\sym - .Llink)
+#endif
+ .endm
+
+ .text
+ENTRY (_start)
+ /* Linux starts us with sp pointing at the conventional Elf layout,
+ but we need to allow two 'caller' words for our ABI convention. */
+ {
+ move r52, sp
+ andi sp, sp, -8
+ }
+ cfi_def_cfa_register (r52)
+ {
+ /* Point sp at base of ABI area; point r4 to the caller-sp word. */
+ ADDI_PTR sp, sp, -(2 * REGSIZE)
+ ADDI_PTR r4, sp, -REGSIZE
+ }
+ {
+ /* Save zero for caller sp in our 'caller' save area, and make
+ sure lr has a zero value, to limit backtraces. */
+ move lr, zero
+ ST r4, zero
+ }
+ {
+ move r0, r52
+ jal _dl_start
+ }
+ /* Save returned start of user program address for later. */
+ move r50, r0
+
+ /* See if we were invoked explicitly with the dynamic loader,
+ in which case we have to adjust the argument vector. */
+ lnk r51; .Llink:
+ pic_addr r4, _dl_skip_args
+ LD4U r4, r4
+ BEQZT r4, .Lno_skip
+
+ /* Load the argc word at the initial sp and adjust it.
+ We basically jump "sp" up over the first few argv entries
+ and write "argc" a little higher up in memory, to be the
+ base of the new kernel-initialized stack area. */
+ LD_PTR r0, r52
+ {
+ sub r0, r0, r4
+ SHL_PTR_ADD r52, r4, r52
+ }
+ {
+ ST_PTR r52, r0
+ SHL_PTR_ADD sp, r4, sp
+ }
+
+.Lno_skip:
+ /* Call_dl_init (_dl_loaded, argc, argv, envp). See elf/start.s
+ for the layout of memory here; r52 is pointing to "+0". */
+ pic_addr r0, _rtld_local
+ {
+ LD_PTR r1, r52 /* load argc in r1 */
+ ADDLI_PTR r2, r52, __SIZEOF_POINTER__ /* point r2 at argv */
+ }
+ {
+ LD_PTR r0, r0 /* yields _rtld_global._ns_loaded */
+ addi r3, r1, 1
+ move lr, zero
+ }
+ {
+ SHL_PTR_ADD r3, r3, r2 /* point r3 at envp */
+ jal _dl_init_internal
+ }
+
+ /* Call user program whose address we saved in r50.
+ We invoke it just like a static binary, but with _dl_fini
+ in r0 so we can distinguish. */
+
+ pic_addr r0, _dl_fini
+ move lr, zero
+ {
+ move sp, r52
+ jr r50
+ }
+
+ /* Tell backtracer to give up (_start has no caller). */
+ info 2 /* INFO_OP_CANNOT_BACKTRACE */
+
+END (_start)
diff --git a/sysdeps/tile/dl-tls.c b/sysdeps/tile/dl-tls.c
new file mode 100644
index 0000000..096539b
--- /dev/null
+++ b/sysdeps/tile/dl-tls.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef SHARED
+/* We provide a fast-path version of __tls_get_addr to allow for
+ the normal case to be fast, both by coding the function tightly,
+ and more importantly by fixing its register clobber API so the
+ compiler can avoid having to set up frames, etc., unnecessarily. */
+#define __tls_get_addr __tls_get_addr_slow
+#endif
+
+#include <elf/dl-tls.c>
diff --git a/sysdeps/tile/dl-tls.h b/sysdeps/tile/dl-tls.h
new file mode 100644
index 0000000..baa0c12
--- /dev/null
+++ b/sysdeps/tile/dl-tls.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+
+/* Type used for the representation of TLS information in the GOT. */
+typedef struct
+{
+ unsigned long int ti_module;
+ unsigned long int ti_offset;
+} tls_index;
+
+/* Fast-path function to get a TLS pointer. */
+extern void *__tls_get_addr (tls_index *ti);
+
+/* The thread pointer points to the first static TLS block. */
+#define TLS_TP_OFFSET 0
+
+/* Dynamic thread vector pointers at the start of each TLS block. */
+#define TLS_DTV_OFFSET 0
+
+/* Compute the value for a GOTTPREL reloc. */
+#define TLS_TPREL_VALUE(sym_map, sym) \
+ ((sym_map)->l_tls_offset + (sym)->st_value - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc. */
+#define TLS_DTPREL_VALUE(sym) \
+ ((sym)->st_value - TLS_DTV_OFFSET)
+
+/* Value used for dtv entries for which the allocation is delayed. */
+#define TLS_DTV_UNALLOCATED ((void *) -1l)
diff --git a/sysdeps/tile/dl-trampoline.S b/sysdeps/tile/dl-trampoline.S
new file mode 100644
index 0000000..486b958
--- /dev/null
+++ b/sysdeps/tile/dl-trampoline.S
@@ -0,0 +1,194 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <arch/abi.h>
+
+/* This function is called via the PLT header, which is called
+ from an individual PLT entry.
+
+ At this point we have several values passed in:
+
+ lr: return address to original user code
+ r28: the tpnt value to pass to _dl_runtime_resolver
+ r29: the PLT index of the invoked jump table entry.
+
+ We set up a frame entry that looks like this (in int_reg_t units):
+
+ +57: r25 return values from function...
+ +56: r24
+ [...]
+ +33: r1
+ +32: r0
+ +31: PLT index
+ +30: tpnt
+ +29: stackframe
+ +28: caller lr
+ +27: r25 arguments to function...
+ +26: r24
+ [...]
+ +3: r1
+ +2: r0
+ +1: standard ABI slot (sp)
+ +0: standard ABI slot (callee lr)
+
+ The entries from "stackframe" up are only used in _dl_profile_resolve.
+ We save and restore r0 through r25, rather than the strictly
+ architected r0 through r9, to support unusual calling conventions;
+ for example, __tls_get_addr takes r0 and returns r0, but promises
+ not to clobber r1 through r24 to support its usual fast path. */
+
+#define FRAME_SP (1 * REGSIZE)
+#define FRAME_REGS (2 * REGSIZE)
+#define FRAME_LR (28 * REGSIZE) /* Must follow FRAME_REGS */
+#define FRAME_STACKFRAME (29 * REGSIZE)
+#define FRAME_TPNT (30 * REGSIZE)
+#define FRAME_INDEX (31 * REGSIZE)
+#define FRAME_RETVAL (32 * REGSIZE)
+
+#define FRAME_SIZE_SMALL (30 * REGSIZE)
+#define FRAME_SIZE_LARGE (58 * REGSIZE)
+
+#define FOR_EACH_REG(f) \
+ f(r0); f(r1); f(r2); f(r3); \
+ f(r4); f(r5); f(r6); f(r7); \
+ f(r8); f(r9); f(r10); f(r11); \
+ f(r12); f(r13); f(r14); f(r15); \
+ f(r16); f(r17); f(r18); f(r19); \
+ f(r20); f(r21); f(r22); f(r23); \
+ f(r24); f(r25)
+
+#define SAVE(REG) { ST r27, REG; ADDI_PTR r27, r27, REGSIZE }
+#define RESTORE(REG) { LD REG, r27; ADDI_PTR r27, r27, REGSIZE }
+
+ .macro dl_resolve, name, profile, framesize
+.text
+.global \name
+.hidden \name
+/* Note that cpp expands ENTRY(\name) incorrectly. */
+.type \name,@function
+.align 8
+\name:
+ cfi_startproc
+ {
+ ST sp, lr
+ move r26, sp
+ }
+ {
+ ADDLI_PTR sp, sp, -\framesize
+ ADDLI_PTR r27, sp, FRAME_SP - \framesize
+ }
+ cfi_def_cfa_offset (\framesize)
+ {
+ ST r27, r26
+ ADDI_PTR r27, r27, FRAME_REGS - FRAME_SP
+ }
+ FOR_EACH_REG(SAVE)
+ {
+ ST r27, lr
+ ADDLI_PTR r27, sp, FRAME_TPNT
+ }
+ cfi_offset (lr, FRAME_LR - \framesize)
+ .if \profile
+ {
+ move r0, r28 /* tpnt value */
+ ST r27, r28
+ ADDI_PTR r27, r27, FRAME_INDEX - FRAME_TPNT
+ }
+ {
+ move r1, r29 /* PLT index */
+ ST r27, r29
+ }
+ {
+ move r2, lr /* retaddr */
+ ADDI_PTR r3, sp, FRAME_REGS /* La_tile_regs pointer */
+ }
+ {
+ ADDLI_PTR r4, sp, FRAME_STACKFRAME /* framesize pointer */
+ jal _dl_profile_fixup
+ }
+ ADDLI_PTR r28, sp, FRAME_STACKFRAME
+ LD_PTR r28, r28
+ BGTZ r28, 1f
+ .else
+ {
+ move r0, r28 /* tpnt value 1 */
+ move r1, r29 /* PLT index 2 */
+ }
+ jal _dl_fixup
+ .endif
+ {
+ /* Copy aside the return value so we can restore r0 below. */
+ move r29, r0
+ /* Set up r27 to let us start restoring registers. */
+ ADDLI_PTR r27, sp, FRAME_REGS
+ }
+ FOR_EACH_REG(RESTORE)
+ .if \profile
+ ADDLI_PTR r28, sp, FRAME_STACKFRAME
+ LD r28, r28
+ BGTZ r28, 1f
+ .endif
+ {
+ /* Restore original user return address. */
+ LD lr, r27
+ /* Pop off our stack frame. */
+ ADDLI_PTR sp, sp, \framesize
+ }
+ cfi_def_cfa_offset (0)
+ jr r29 /* Transfer control to freshly loaded code. */
+ jrp lr /* Keep backtracer happy. */
+
+ .if \profile
+1: jalr r29 /* Call resolved function. */
+ {
+ ADDLI_PTR r28, sp, FRAME_TPNT
+ ADDLI_PTR r27, sp, FRAME_RETVAL
+ }
+ FOR_EACH_REG(SAVE)
+ {
+ LD r0, r28
+ ADDI_PTR r28, r28, FRAME_INDEX - FRAME_TPNT
+ }
+ {
+ LD r1, r28
+ ADDLI_PTR r2, sp, FRAME_REGS
+ }
+ {
+ ADDLI_PTR r3, sp, FRAME_RETVAL
+ jal _dl_call_pltexit
+ }
+ {
+ ADDLI_PTR lr, sp, FRAME_LR
+ ADDLI_PTR r27, sp, FRAME_RETVAL
+ }
+ FOR_EACH_REG(RESTORE)
+ {
+ LD lr, lr
+ ADDLI_PTR sp, sp, \framesize
+ }
+ jrp lr
+ .endif
+END (\name)
+ .endm
+
+ dl_resolve _dl_runtime_resolve, 0, FRAME_SIZE_SMALL
+#ifndef PROF
+ dl_resolve _dl_runtime_profile, 1, FRAME_SIZE_LARGE
+#endif
diff --git a/sysdeps/tile/elf/start.S b/sysdeps/tile/elf/start.S
new file mode 100644
index 0000000..71a2c8b
--- /dev/null
+++ b/sysdeps/tile/elf/start.S
@@ -0,0 +1,184 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ In addition to the permissions in the GNU Lesser General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file with other
+ programs, and to distribute those programs without any restriction
+ coming from the use of this file. (The GNU Lesser General Public
+ License restrictions do apply in other respects; for example, they
+ cover modification of the file, and distribution when not linked
+ into another program.)
+
+ Note that people who make modified versions of this file are not
+ obligated to grant this special exception for their modified
+ versions; it is their choice whether to do so. The GNU Lesser
+ General Public License gives permission to release a modified
+ version without this exception; this exception also makes it
+ possible to release a modified version which carries forward this
+ exception.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* This is the canonical entry point, usually the first thing in the text
+ segment. The ELF standard tells us that the stack is set up like this on
+ entry (the left side is the offset from "sp"), in units of
+ __SIZEOF_POINTER__ entries:
+
+ +0 argc
+ +1 argv[0]
+ ...
+ +(argc+1) NULL
+ +(argc+2) envp[0]
+ ...
+ NULL
+ ... ElfInfo
+
+ The ElfInfo is pairs of key/value long words following the envp
+ pointers and terminated by a zero-valued key.
+
+ Although not mandated by the standard, it happens to be the case
+ that we store the actual argv and envp strings immediately after
+ the ElfInfo data on the stack.
+
+ On entry r0 points to the shared library termination function, or 0
+ if there isn't one.
+*/
+
+#include <features.h>
+#include <sysdep.h>
+#include <arch/abi.h>
+
+ .text
+ .global _start
+ .type _start,@function
+ .align 8
+_start:
+ /* Linux starts us with sp pointing at the conventional Elf layout,
+ but we need to allow two "caller" words for our ABI convention. */
+ {
+ /* Load argc (stored as a "long", equivalent to a pointer type). */
+ LD_PTR r1, sp
+
+ /* Save incoming 'sp', which points to the Elf argument block. */
+ move r52, sp
+ }
+
+ {
+ /* Allocate stack frame callee space for __libc_start_main. */
+ ADDI_PTR r12, sp, -(2 * REGSIZE)
+ }
+
+ {
+ /* Get our PC. */
+ lnk r13
+
+ /* sp is not necessarily properly aligned on startup because
+ of the way ld.so pops off leading argv elements. So align it. */
+ andi sp, r12, -8
+ }
+.Lmy_pc:
+
+ {
+ /* Pass the address of the shared library termination function. */
+ move r5, r0
+
+ /* Compute location where __libc_start_main's caller is supposed to
+ store its frame pointer. */
+ ADDI_PTR r12, sp, REGSIZE
+
+ /* Zero out callee space for return address. Unnecessary but free.
+ This is just paranoia to help backtracing not go awry. */
+ ST sp, zero
+ }
+ {
+ /* Zero out our frame pointer for __libc_start_main. */
+ ST r12, zero
+
+ /* Zero out lr to make __libc_start_main the end of backtrace. */
+ move lr, zero
+
+ /* Compute a pointer to argv. envp will be determined
+ later in __libc_start_main. We set up the first argument
+ (the address of main) below. */
+ ADDI_PTR r2, r52, __SIZEOF_POINTER__
+ }
+ {
+ /* Pass the highest stack address to user code. */
+ ADDI_PTR r6, sp, (2 * REGSIZE)
+
+ /* Pass address of main() in r0, and of our own entry
+ points to .fini and .init in r3 and r4. */
+#ifdef __tilegx__
+ moveli r0, hw2_last(main - .Lmy_pc)
+ }
+ {
+ moveli r3, hw2_last(__libc_csu_init - .Lmy_pc)
+ shl16insli r0, r0, hw1(main - .Lmy_pc)
+ }
+ {
+ shl16insli r3, r3, hw1(__libc_csu_init - .Lmy_pc)
+ shl16insli r0, r0, hw0(main - .Lmy_pc)
+ }
+ {
+ shl16insli r3, r3, hw0(__libc_csu_init - .Lmy_pc)
+ moveli r4, hw2_last(__libc_csu_fini - .Lmy_pc)
+ }
+ {
+ ADD_PTR r0, r0, r13
+ shl16insli r4, r4, hw1(__libc_csu_fini - .Lmy_pc)
+ }
+ {
+ ADD_PTR r3, r3, r13
+ shl16insli r4, r4, hw0(__libc_csu_fini - .Lmy_pc)
+ }
+ {
+ ADD_PTR r4, r4, r13
+#else
+ addli r0, r13, lo16(main - .Lmy_pc)
+ }
+ {
+ auli r0, r0, ha16(main - .Lmy_pc)
+ addli r3, r13, lo16(__libc_csu_init - .Lmy_pc)
+ }
+ {
+ auli r3, r3, ha16(__libc_csu_init - .Lmy_pc)
+ addli r4, r13, lo16(__libc_csu_fini - .Lmy_pc)
+ }
+ {
+ auli r4, r4, ha16(__libc_csu_fini - .Lmy_pc)
+
+#endif
+
+ /* Call the user's main function, and exit with its value.
+ But let the libc call main. */
+ j plt(__libc_start_main)
+ }
+ {
+ /* Tell backtracer to give up (_start has no caller). */
+ info INFO_OP_CANNOT_BACKTRACE
+ }
+.size _start, .-_start
+
+/* Define a symbol for the first piece of initialized data. */
+ .data
+ .global __data_start
+ .align 8
+__data_start:
+ .long 0
+ .weak data_start
+ data_start = __data_start
diff --git a/sysdeps/tile/fegetenv.c b/sysdeps/tile/fegetenv.c
new file mode 100644
index 0000000..ff84609
--- /dev/null
+++ b/sysdeps/tile/fegetenv.c
@@ -0,0 +1,29 @@
+/* Store current floating-point environment.
+ Copyright (C) 1997, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+
+int
+__fegetenv (fenv_t *envp)
+{
+ /* As a no-op, this always succeeds. */
+ return 0;
+}
+libm_hidden_ver (__fegetenv, fegetenv)
diff --git a/sysdeps/tile/fegetround.c b/sysdeps/tile/fegetround.c
new file mode 100644
index 0000000..837fd59
--- /dev/null
+++ b/sysdeps/tile/fegetround.c
@@ -0,0 +1,27 @@
+/* Return current rounding direction.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+
+int
+fegetround (void)
+{
+ return FE_TONEAREST;
+}
diff --git a/sysdeps/tile/feholdexcpt.c b/sysdeps/tile/feholdexcpt.c
new file mode 100644
index 0000000..384b696
--- /dev/null
+++ b/sysdeps/tile/feholdexcpt.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+
+/* Tile has no exception flags, so this routine can be a no-op. */
+int
+feholdexcept (fenv_t *envp)
+{
+ return 0;
+}
+libm_hidden_def (feholdexcept)
diff --git a/sysdeps/tile/fesetenv.c b/sysdeps/tile/fesetenv.c
new file mode 100644
index 0000000..ceb45e4
--- /dev/null
+++ b/sysdeps/tile/fesetenv.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+#include <shlib-compat.h>
+
+/* The only way to get an initialized fenv_t on Tile is with feholdexcept()
+ or via FE_DFL_ENV, either of which restores the environment to its
+ normal state, i.e. FE_DFL_ENV. */
+int
+__fesetenv (const fenv_t *envp)
+{
+ return 0;
+}
+libm_hidden_ver (__fesetenv, fesetenv)
+versioned_symbol (libm, __fesetenv, fesetenv, GLIBC_2_2);
diff --git a/sysdeps/tile/fesetround.c b/sysdeps/tile/fesetround.c
new file mode 100644
index 0000000..8954a65
--- /dev/null
+++ b/sysdeps/tile/fesetround.c
@@ -0,0 +1,28 @@
+/* Set current rounding direction.
+ Copyright (C) 1997, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+
+int
+fesetround (int round)
+{
+ return (round == FE_TONEAREST) ? 0 : 1;
+}
+libm_hidden_def (fesetround)
diff --git a/sysdeps/tile/feupdateenv.c b/sysdeps/tile/feupdateenv.c
new file mode 100644
index 0000000..65cb318
--- /dev/null
+++ b/sysdeps/tile/feupdateenv.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <fenv.h>
+
+/* Tile has no exception flags, so this routine can be a no-op. */
+int
+__feupdateenv (const fenv_t *envp)
+{
+ return 0;
+}
+weak_alias (__feupdateenv, feupdateenv)
diff --git a/sysdeps/tile/ffs.c b/sysdeps/tile/ffs.c
new file mode 100644
index 0000000..498559c
--- /dev/null
+++ b/sysdeps/tile/ffs.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <limits.h>
+#define ffsl __something_else
+#include <string.h>
+
+#undef ffs
+int
+__ffs (int x)
+{
+ return __builtin_ffs (x);
+}
+weak_alias (__ffs, ffs)
+libc_hidden_builtin_def (ffs)
+
+#undef ffsll
+int
+ffsll (long long x)
+{
+ return __builtin_ffsll (x);
+}
+
+#undef ffsl
+#if ULONG_MAX == UINT_MAX
+weak_alias (__ffs, ffsl)
+#else
+weak_alias (ffsll, ffsl)
+#endif
diff --git a/sysdeps/tile/ffsll.c b/sysdeps/tile/ffsll.c
new file mode 100644
index 0000000..180eaa8
--- /dev/null
+++ b/sysdeps/tile/ffsll.c
@@ -0,0 +1 @@
+/* This function is defined in ffs.c. */
diff --git a/sysdeps/tile/gccframe.h b/sysdeps/tile/gccframe.h
new file mode 100644
index 0000000..041d3d8
--- /dev/null
+++ b/sysdeps/tile/gccframe.h
@@ -0,0 +1,22 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define FIRST_PSEUDO_REGISTER 64
+
+#include <sysdeps/generic/gccframe.h>
diff --git a/sysdeps/tile/jmpbuf-offsets.h b/sysdeps/tile/jmpbuf-offsets.h
new file mode 100644
index 0000000..ce4f1b2
--- /dev/null
+++ b/sysdeps/tile/jmpbuf-offsets.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* We don't use most of these symbols; they are here for documentation. */
+#define JB_R30 0
+#define JB_R31 1
+#define JB_R32 2
+#define JB_R33 3
+#define JB_R34 4
+#define JB_R35 5
+#define JB_R36 6
+#define JB_R37 7
+#define JB_R38 8
+#define JB_R39 9
+#define JB_R40 10
+#define JB_R41 11
+#define JB_R42 12
+#define JB_R43 13
+#define JB_R44 14
+#define JB_R45 15
+#define JB_R46 16
+#define JB_R47 17
+#define JB_R48 18
+#define JB_R49 19
+#define JB_R50 20
+#define JB_R51 21
+#define JB_FP 22 /* r52 */
+#define JB_TP 23 /* r53 */
+#define JB_SP 24 /* r54 */
+#define JB_PC 25 /* normally LR, r55 */
+#define JB_ICS 26 /* interrupt critical section bit */
+
+/* We save space for some extra state to accomodate future changes. */
+#define JB_LEN 32 /* number of words */
+
+#define JB_SIZE (JB_LEN * REGSIZE)
+
+/* Helper macro used by all the setjmp/longjmp assembly code. */
+#define FOR_EACH_CALLEE_SAVED_REG(f) \
+ .no_require_canonical_reg_names; f(r30); f(r31); \
+ f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \
+ f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \
+ f(r48); f(r49); f(r50); f(r51); f(r52); f(r53); f(r54); f(r55)
+
+/* Helper for generic ____longjmp_chk(). */
+#define JB_FRAME_ADDRESS(buf) \
+ ((void *) (unsigned long) (buf[JB_SP]))
diff --git a/sysdeps/tile/jmpbuf-unwind.h b/sysdeps/tile/jmpbuf-unwind.h
new file mode 100644
index 0000000..624a014
--- /dev/null
+++ b/sysdeps/tile/jmpbuf-unwind.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+ Based on work contributed by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <setjmp.h>
+#include <jmpbuf-offsets.h>
+#include <stdint.h>
+#include <unwind.h>
+#include <sysdep.h>
+
+/* Test if longjmp to JMPBUF would unwind the frame
+ containing a local variable at ADDRESS. */
+#define _JMPBUF_UNWINDS(jmpbuf, address, demangle) \
+ ((void *) (address) < (void *) demangle ((jmpbuf)[JB_SP]))
+
+#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \
+ _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj)
+
+static inline uintptr_t __attribute__ ((unused))
+_jmpbuf_sp (__jmp_buf regs)
+{
+ uintptr_t sp = regs[JB_SP];
+#ifdef PTR_DEMANGLE
+ PTR_DEMANGLE (sp);
+#endif
+ return sp;
+}
+
+#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \
+ ((uintptr_t) (_address) - (_adj) < _jmpbuf_sp (_jmpbuf) - (_adj))
+
+/* We use the normal longjmp for unwinding. */
+#define __libc_unwind_longjmp(buf, val) __libc_longjmp (buf, val)
diff --git a/sysdeps/tile/ldsodefs.h b/sysdeps/tile/ldsodefs.h
new file mode 100644
index 0000000..e90de56
--- /dev/null
+++ b/sysdeps/tile/ldsodefs.h
@@ -0,0 +1,41 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _TILE_LDSODEFS_H
+#define _TILE_LDSODEFS_H 1
+
+#include <elf.h>
+
+struct La_tile_regs;
+struct La_tile_retval;
+
+#define ARCH_PLTENTER_MEMBERS \
+ ElfW(Addr) (*tile_gnu_pltenter) (ElfW(Sym) *, unsigned int, uintptr_t *, \
+ uintptr_t *, struct La_tile_regs *, \
+ unsigned int *, const char *, \
+ long int *)
+
+#define ARCH_PLTEXIT_MEMBERS \
+ ElfW(Addr) (*tile_gnu_pltexit) (ElfW(Sym) *, unsigned int, uintptr_t *, \
+ uintptr_t *, struct La_tile_regs *, \
+ struct La_tile_retval *, const char *)
+
+#include_next <ldsodefs.h>
+
+#endif
diff --git a/sysdeps/tile/libc-tls.c b/sysdeps/tile/libc-tls.c
new file mode 100644
index 0000000..04d26a7
--- /dev/null
+++ b/sysdeps/tile/libc-tls.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <csu/libc-tls.c>
+
+#define REQUEST_ASSEMBLER_MACROS
+#include <sysdep.h>
+#include <dl-tls.h>
+#include <tcb-offsets.h>
+
+#ifndef __OPTIMIZE__
+# error "Must compile with optimization to avoid frame setup."
+#endif
+
+/* On TILE, linker optimizations are not required, so __tls_get_addr
+ can be called even in statically linked binaries. In this case module
+ must be always 1 and PT_TLS segment exist in the binary, otherwise it
+ would not link. Written in assembly so that it conforms to the
+ ABI requirement that only registers r25..r29 can be clobbered. */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+ /* dtv_t *dtv = THREAD_DTV ();
+ return (char *) dtv[1].pointer.val + ti->ti_offset; */
+
+ void *retval;
+#define _helper(_ADDI_PTR, _ADD_PTR, _LD_PTR) \
+ asm("{" \
+ #_ADDI_PTR" r29, tp, %1\n" \
+ #_ADDI_PTR" r0, r0, %2\n" \
+ "}\n" \
+ #_LD_PTR" r29, r29\n" /* r29 = dtv */ \
+ "{\n" \
+ #_LD_PTR" r0, r0\n" /* r0 = ti->ti_offset */ \
+ #_ADDI_PTR" r29, r29, %3\n" /* r29 = &dtv[1] */ \
+ "}\n" \
+ #_LD_PTR" r29, r29\n" /* r29 = dtv[1].pointer.val */ \
+ "{\n" \
+ #_ADD_PTR" r0, r0, r29\n" \
+ " jrp lr\n" \
+ "}\n" \
+ : "=R00" (retval) \
+ : "n" (DTV_OFFSET), "n" (sizeof(void*)), "n" (sizeof(dtv_t)), "R00" (ti)\
+ : "r29")
+#define helper(_ADDI_PTR, _ADD_PTR, _LD_PTR) \
+ _helper (_ADDI_PTR, _ADD_PTR, _LD_PTR)
+
+ helper (ADDI_PTR, ADD_PTR, LD_PTR);
+
+ return retval;
+}
diff --git a/sysdeps/tile/machine-gmon.h b/sysdeps/tile/machine-gmon.h
new file mode 100644
index 0000000..473707b
--- /dev/null
+++ b/sysdeps/tile/machine-gmon.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define _MCOUNT_DECL(from, self) \
+ void __mcount_internal (u_long from, u_long self)
+
+/* Call __mcount_internal with our the return PC for our caller, and
+ the return PC our caller will return to. Empty since we use an
+ assembly stub instead. */
+#define MCOUNT
diff --git a/sysdeps/tile/nptl/Makefile b/sysdeps/tile/nptl/Makefile
new file mode 100644
index 0000000..24990a2
--- /dev/null
+++ b/sysdeps/tile/nptl/Makefile
@@ -0,0 +1,21 @@
+# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307 USA.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/tile/nptl/pthread_spin_lock.c b/sysdeps/tile/nptl/pthread_spin_lock.c
new file mode 100644
index 0000000..ee05562
--- /dev/null
+++ b/sysdeps/tile/nptl/pthread_spin_lock.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include "pthreadP.h"
+#include <arch/spr_def.h>
+#include <atomic.h>
+
+/* Bound point for bounded exponential backoff */
+#define BACKOFF_MAX 2048
+
+/* Initial cycle delay for exponential backoff */
+#define BACKOFF_START 32
+
+#ifdef __tilegx__
+/* Use cmpexch() after the initial fast-path exch to avoid
+ invalidating the cache line of the lock holder. */
+# define TNS(p) atomic_exchange_acq((p), 1)
+# define CMPTNS(p) atomic_compare_and_exchange_val_acq((p), 1, 0)
+#else
+# define TNS(p) __insn_tns(p)
+# define CMPTNS(p) __insn_tns(p)
+# define SPR_CYCLE SPR_CYCLE_LOW /* The low 32 bits are sufficient. */
+#endif
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+ if (__builtin_expect (TNS (lock) != 0, 0))
+ {
+ unsigned int backoff = BACKOFF_START;
+ while (CMPTNS (lock) != 0)
+ {
+ unsigned int start = __insn_mfspr (SPR_CYCLE);
+ while (__insn_mfspr (SPR_CYCLE) - start < backoff)
+ ;
+ if (backoff < BACKOFF_MAX)
+ backoff *= 2;
+ }
+ }
+ return 0;
+}
diff --git a/sysdeps/tile/nptl/pthread_spin_trylock.c b/sysdeps/tile/nptl/pthread_spin_trylock.c
new file mode 100644
index 0000000..f111cc7
--- /dev/null
+++ b/sysdeps/tile/nptl/pthread_spin_trylock.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include "pthreadP.h"
+#include <errno.h>
+
+#ifdef __tilegx__
+#define TNS(p) __insn_exch4((p), 1)
+#else
+#define TNS(p) __insn_tns(p)
+#endif
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+ return (TNS (lock) == 0) ? 0 : EBUSY;
+}
diff --git a/sysdeps/tile/nptl/pthreaddef.h b/sysdeps/tile/nptl/pthreaddef.h
new file mode 100644
index 0000000..4ba1adb
--- /dev/null
+++ b/sysdeps/tile/nptl/pthreaddef.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Default stack size. */
+#define ARCH_STACK_DEFAULT_SIZE (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning. */
+#define STACK_ALIGN 16
+
+/* Minimal stack size after allocating thread descriptor and guard size. */
+#define MINIMAL_REST_STACK 2048
+
+/* Alignment requirement for TCB. */
+#define TCB_ALIGNMENT 16
+
+
+/* Location of current stack frame. */
+#define CURRENT_STACK_FRAME __builtin_frame_address (0)
+
+/* XXX Until we have a better place keep the definitions here. */
+
+#define __exit_thread_inline(val) \
+ INLINE_SYSCALL (exit, 1, (val))
diff --git a/sysdeps/tile/nptl/tcb-offsets.sym b/sysdeps/tile/nptl/tcb-offsets.sym
new file mode 100644
index 0000000..6740bc9
--- /dev/null
+++ b/sysdeps/tile/nptl/tcb-offsets.sym
@@ -0,0 +1,17 @@
+#define SHARED /* needed to get struct rtld_global from <ldsodefs.h> */
+#include <sysdep.h>
+#include <tls.h>
+#include <ldsodefs.h>
+
+--
+
+-- Abuse tls.h macros to derive offsets relative to the thread register.
+#define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads)
+PID_OFFSET thread_offsetof (pid)
+TID_OFFSET thread_offsetof (tid)
+POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+FEEDBACK_DATA_OFFSET (offsetof (tcbhead_t, feedback_data) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+DTV_OFFSET (offsetof (tcbhead_t, dtv) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation)
diff --git a/sysdeps/tile/nptl/tls.h b/sysdeps/tile/nptl/tls.h
new file mode 100644
index 0000000..106451a
--- /dev/null
+++ b/sysdeps/tile/nptl/tls.h
@@ -0,0 +1,195 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _TLS_H
+#define _TLS_H 1
+
+# include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv. */
+typedef union dtv
+{
+ size_t counter;
+ struct
+ {
+ void *val;
+ bool is_static;
+ } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information. */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks. */
+# define TLS_DTV_AT_TP 1
+
+/* We use the multiple_threads field in the pthread struct */
+#define TLS_MULTIPLE_THREADS_IN_TCB 1
+
+/* Get the thread descriptor definition. */
+# include <nptl/descr.h>
+
+/* The stack_guard is accessed directly by GCC -fstack-protector code,
+ so it is a part of public ABI. The dtv and pointer_guard fields
+ are private. */
+typedef struct
+{
+ void *feedback_data;
+ uintptr_t pointer_guard;
+ uintptr_t stack_guard;
+ dtv_t *dtv;
+} tcbhead_t;
+
+/* This is the size of the initial TCB. Because our TCB is before the thread
+ pointer, we don't need this. */
+# define TLS_INIT_TCB_SIZE 0
+
+/* Alignment requirements for the initial TCB. */
+# define TLS_INIT_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size of the TCB. Because our TCB is before the thread
+ pointer, we don't need this. */
+# define TLS_TCB_SIZE 0
+
+/* Alignment requirements for the TCB. */
+# define TLS_TCB_ALIGN __alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB. */
+# define TLS_PRE_TCB_SIZE \
+ (sizeof (struct pthread) \
+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* Return the thread descriptor (tp) for the current thread. */
+register void *__thread_pointer asm ("tp");
+
+/* The thread pointer (in hardware register tp) points to the end of
+ the TCB. The pthread_descr structure is immediately in front of the TCB. */
+# define TLS_TCB_OFFSET 0
+
+/* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+# define INSTALL_DTV(tcbp, dtvp) \
+ (((tcbhead_t *) (tcbp))[-1].dtv = (dtvp) + 1)
+
+/* Install new dtv for current thread. */
+# define INSTALL_NEW_DTV(dtv) (THREAD_DTV() = (dtv))
+
+/* Return dtv of given thread descriptor. */
+# define GET_DTV(tcbp) (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer (tp). */
+# define TLS_INIT_TP(tcbp, secondcall) \
+ (__thread_pointer = (char *)(tcbp) + TLS_TCB_OFFSET, NULL)
+
+/* Return the address of the dtv for the current thread. */
+# define THREAD_DTV() \
+ (((tcbhead_t *) (__thread_pointer - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread. */
+# define THREAD_SELF \
+ ((struct pthread *) (__thread_pointer \
+ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF. */
+#ifdef __tilegx__
+# define DB_THREAD_SELF \
+ REGISTER (64, 64, REG_TP * 8, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+#else
+# define DB_THREAD_SELF \
+ REGISTER (32, 32, REG_TP * 4, - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+#endif
+
+/* Read member of the thread descriptor directly. */
+# define THREAD_GETMEM(descr, member) (descr->member)
+
+/* Same as THREAD_GETMEM, but the member offset can be non-constant. */
+# define THREAD_GETMEM_NC(descr, member, idx) \
+ (descr->member[idx])
+
+/* Set member of the thread descriptor directly. */
+# define THREAD_SETMEM(descr, member, value) \
+ (descr->member = (value))
+
+/* Same as THREAD_SETMEM, but the member offset can be non-constant. */
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+ (descr->member[idx] = (value))
+
+/* Set the stack guard field in TCB head. */
+# define THREAD_SET_STACK_GUARD(value) \
+ (((tcbhead_t *) ((char *) __thread_pointer \
+ - TLS_TCB_OFFSET))[-1].stack_guard = (value))
+# define THREAD_COPY_STACK_GUARD(descr) \
+ (((tcbhead_t *) ((char *) (descr) \
+ + TLS_PRE_TCB_SIZE))[-1].stack_guard \
+ = ((tcbhead_t *) ((char *) __thread_pointer \
+ - TLS_TCB_OFFSET))[-1].stack_guard)
+
+/* Set the pointer guard field in TCB head. */
+# define THREAD_GET_POINTER_GUARD() \
+ (((tcbhead_t *) ((char *) __thread_pointer \
+ - TLS_TCB_OFFSET))[-1].pointer_guard)
+# define THREAD_SET_POINTER_GUARD(value) \
+ (THREAD_GET_POINTER_GUARD () = (value))
+# define THREAD_COPY_POINTER_GUARD(descr) \
+ (((tcbhead_t *) ((char *) (descr) \
+ + TLS_PRE_TCB_SIZE))[-1].pointer_guard \
+ = THREAD_GET_POINTER_GUARD())
+
+/* l_tls_offset == 0 is perfectly valid on Tile, so we have to use some
+ different value to mean unset l_tls_offset. */
+# define NO_TLS_OFFSET -1
+
+/* Get and set the global scope generation counter in struct pthread. */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED 1
+#define THREAD_GSCOPE_FLAG_WAIT 2
+#define THREAD_GSCOPE_RESET_FLAG() \
+ do \
+ { int __res \
+ = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag, \
+ THREAD_GSCOPE_FLAG_UNUSED); \
+ if (__res == THREAD_GSCOPE_FLAG_WAIT) \
+ lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_SET_FLAG() \
+ do \
+ { \
+ THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED; \
+ atomic_write_barrier (); \
+ } \
+ while (0)
+#define THREAD_GSCOPE_WAIT() \
+ GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/sysdeps/tile/preconfigure b/sysdeps/tile/preconfigure
new file mode 100644
index 0000000..61e1f96
--- /dev/null
+++ b/sysdeps/tile/preconfigure
@@ -0,0 +1,14 @@
+# This is a -*- sh -*-
+case "$machine" in
+ tilepro)
+ base_machine=tile machine=tile/tilepro ;;
+ tilegx)
+ base_machine=tile machine=tile/tilegx/tilegx64 ;;
+ tilegx32)
+ base_machine=tile machine=tile/tilegx/tilegx32 ;;
+esac
+case "$machine" in
+ tile*)
+ libc_commonpagesize=0x10000
+ libc_relro_required=yes ;;
+esac
diff --git a/sysdeps/tile/s_fma.c b/sysdeps/tile/s_fma.c
new file mode 100644
index 0000000..355b4ed
--- /dev/null
+++ b/sysdeps/tile/s_fma.c
@@ -0,0 +1,3 @@
+/* Although tile uses ieee754/dbl-64, it does not support the
+ rounding modes required to use the standard dbl-64 s_fma.c. */
+#include <math/s_fma.c>
diff --git a/sysdeps/tile/s_fmaf.c b/sysdeps/tile/s_fmaf.c
new file mode 100644
index 0000000..caa8e40
--- /dev/null
+++ b/sysdeps/tile/s_fmaf.c
@@ -0,0 +1,3 @@
+/* Although tile uses ieee754/dbl-64, it does not support the
+ rounding modes required to use the standard dbl-64 s_fmaf.c. */
+#include <math/s_fmaf.c>
diff --git a/sysdeps/tile/setjmp.S b/sysdeps/tile/setjmp.S
new file mode 100644
index 0000000..950e4ca
--- /dev/null
+++ b/sysdeps/tile/setjmp.S
@@ -0,0 +1,47 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdep.h>
+#include <jmpbuf-offsets.h>
+#include <feedback-asm.h>
+
+ .text
+
+ /* Keep traditional entry points in with sigsetjmp(). */
+ENTRY(setjmp)
+ { movei r1, 1; j 1f }
+END(setjmp)
+
+ENTRY(_setjmp)
+ { movei r1, 0; j 1f }
+END(_setjmp)
+libc_hidden_def (_setjmp)
+
+ENTRY(__sigsetjmp)
+1:
+ move r2, r0
+
+#define SAVE(r) { ST r2, r ; ADDI_PTR r2, r2, REGSIZE }
+ FOR_EACH_CALLEE_SAVED_REG(SAVE)
+
+ mfspr r3, INTERRUPT_CRITICAL_SECTION
+ ST r2, r3
+ j plt(__sigjmp_save)
+ jrp lr /* Keep the backtracer happy. */
+END(__sigsetjmp)
diff --git a/sysdeps/tile/stackinfo.h b/sysdeps/tile/stackinfo.h
new file mode 100644
index 0000000..e3233ac
--- /dev/null
+++ b/sysdeps/tile/stackinfo.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* This file contains a bit of information about the stack allocation
+ of the processor. */
+
+#ifndef _STACKINFO_H
+#define _STACKINFO_H 1
+
+#include <elf.h>
+
+/* On tile the stack grows down. */
+#define _STACK_GROWS_DOWN 1
+
+/* Default to a non-executable stack. */
+#define DEFAULT_STACK_PERMS (PF_R|PF_W)
+
+/* Access to the stack pointer. The macros are used in alloca_account
+ for which they need to act as barriers as well, hence the additional
+ (unnecessary) parameters. */
+#define stackinfo_get_sp() \
+ ({ void *p__; asm volatile ("move %0, sp" : "=r" (p__)); p__; })
+#if defined __tilegx__ && __WORDSIZE == 32
+#define __stackinfo_sub "subx"
+#else
+#define __stackinfo_sub "sub"
+#endif
+#define stackinfo_sub_sp(ptr) \
+ ({ ptrdiff_t d__; \
+ asm volatile (__stackinfo_sub " %0, %0, sp" : "=r" (d__) : "0" (ptr)); \
+ d__; })
+
+#endif /* stackinfo.h */
diff --git a/sysdeps/tile/sysdep.h b/sysdeps/tile/sysdep.h
new file mode 100644
index 0000000..57d8260
--- /dev/null
+++ b/sysdeps/tile/sysdep.h
@@ -0,0 +1,118 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <sysdeps/generic/sysdep.h>
+#include <bits/wordsize.h>
+#include <arch/abi.h>
+
+#ifndef HAVE_ELF
+# error "ELF is assumed."
+#endif
+
+#ifndef NO_UNDERSCORES
+# error "User-label prefix (underscore) assumed absent."
+#endif
+
+#if defined __ASSEMBLER__ || defined REQUEST_ASSEMBLER_MACROS
+
+/* Make use of .type and .size directives. */
+#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
+#define ASM_SIZE_DIRECTIVE(name) .size name,.-name;
+
+/* Define an entry point visible from C. */
+#define ENTRY(name) \
+ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \
+ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \
+ .align 8; \
+ C_LABEL(name) \
+ cfi_startproc; \
+ CALL_MCOUNT
+
+#undef END
+#define END(name) \
+ cfi_endproc; \
+ ASM_SIZE_DIRECTIVE(name)
+
+/* Since C identifiers are not normally prefixed with an underscore
+ on this system, the asm identifier `syscall_error' intrudes on the
+ C name space. Make sure we use an innocuous name. */
+#define syscall_error __syscall_error
+#define mcount _mcount
+
+/* If compiled for profiling, call `mcount' at the start of each function.
+ The mcount code requires the caller PC in r10. The `mcount' function
+ sets lr back to the value r10 had on entry when it returns. */
+#ifdef PROF
+#define CALL_MCOUNT { move r10, lr; jal mcount }
+#else
+#define CALL_MCOUNT /* Do nothing. */
+#endif
+
+/* Local label name for asm code. */
+#define L(name) .L##name
+
+/* Specify the size in bytes of a machine register. */
+#ifdef __tilegx__
+#define REGSIZE 8
+#else
+#define REGSIZE 4
+#endif
+
+/* Support a limited form of shared assembly between tile and tilegx.
+ The presumption is that LD/ST are used for manipulating registers.
+ Since opcode parsing is case-insensitive, we don't need to provide
+ definitions for these on tilegx. */
+#ifndef __tilegx__
+#define LD lw
+#define LD4U lw
+#define ST sw
+#define ST4 sw
+#define BNEZ bnz
+#define BEQZ bz
+#define BEQZT bzt
+#define BGTZ bgz
+#define CMPEQI seqi
+#define CMPEQ seq
+#define CMOVEQZ mvz
+#define CMOVNEZ mvnz
+#endif
+
+/* Provide "pointer-oriented" instruction variants. These differ not
+ just for tile vs tilegx, but also for tilegx -m64 vs -m32. */
+#if defined __tilegx__ && __WORDSIZE == 32
+#define ADD_PTR addx
+#define ADDI_PTR addxi
+#define ADDLI_PTR addxli
+#define LD_PTR ld4s
+#define ST_PTR st4
+#define SHL_PTR_ADD shl2add
+#else
+#define ADD_PTR add
+#define ADDI_PTR addi
+#define ADDLI_PTR addli
+#define LD_PTR LD
+#define ST_PTR ST
+#ifdef __tilegx__
+#define SHL_PTR_ADD shl3add
+#else
+#define SHL_PTR_ADD s2a
+#endif
+#endif
+
+#endif /* __ASSEMBLER__ */
diff --git a/sysdeps/tile/tilegx/Makefile b/sysdeps/tile/tilegx/Makefile
new file mode 100644
index 0000000..49517fa
--- /dev/null
+++ b/sysdeps/tile/tilegx/Makefile
@@ -0,0 +1,3 @@
+ifeq ($(subdir),debug)
+sysdep_routines += tile-desc
+endif
diff --git a/sysdeps/tile/tilegx/bits/atomic.h b/sysdeps/tile/tilegx/bits/atomic.h
new file mode 100644
index 0000000..1cb4e2b
--- /dev/null
+++ b/sysdeps/tile/tilegx/bits/atomic.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+#include <arch/spr_def.h>
+
+/* Pick appropriate 8- or 4-byte instruction. */
+#define __atomic_update(mem, v, op) \
+ ((__typeof (*(mem))) (__typeof (*(mem) - *(mem))) \
+ ((sizeof (*(mem)) == 8) ? \
+ __insn_##op ((void *) (mem), (int64_t) (__typeof((v) - (v))) (v)) : \
+ (sizeof (*(mem)) == 4) ? \
+ __insn_##op##4 ((void *) (mem), (int32_t) (__typeof ((v) - (v))) (v)) : \
+ __atomic_error_bad_argument_size()))
+
+#define atomic_compare_and_exchange_val_acq(mem, n, o) \
+ ({ __insn_mtspr (SPR_CMPEXCH_VALUE, (int64_t) (__typeof ((o) - (o))) (o)); \
+ __atomic_update (mem, n, cmpexch); })
+#define atomic_exchange_acq(mem, newvalue) \
+ __atomic_update (mem, newvalue, exch)
+#define atomic_exchange_and_add(mem, value) \
+ __atomic_update (mem, value, fetchadd)
+#define atomic_and_val(mem, mask) \
+ __atomic_update (mem, mask, fetchand)
+#define atomic_or_val(mem, mask) \
+ __atomic_update (mem, mask, fetchor)
+#define atomic_decrement_if_positive(mem) \
+ __atomic_update (mem, -1, fetchaddgez)
+
+#include <sysdeps/tile/bits/atomic.h>
+
+#endif /* bits/atomic.h */
diff --git a/sysdeps/tile/tilegx/bits/wordsize.h b/sysdeps/tile/tilegx/bits/wordsize.h
new file mode 100644
index 0000000..78f3481
--- /dev/null
+++ b/sysdeps/tile/tilegx/bits/wordsize.h
@@ -0,0 +1,8 @@
+/* Determine the wordsize from the preprocessor defines. */
+
+#ifdef __LP64__
+# define __WORDSIZE 64
+# define __WORDSIZE_COMPAT32 1
+#else
+# define __WORDSIZE 32
+#endif
diff --git a/sysdeps/tile/tilegx/memchr.c b/sysdeps/tile/tilegx/memchr.c
new file mode 100644
index 0000000..52a20b6
--- /dev/null
+++ b/sysdeps/tile/tilegx/memchr.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+void *
+__memchr (const void *s, int c, size_t n)
+{
+ const uint64_t *last_word_ptr;
+ const uint64_t *p;
+ const char *last_byte_ptr;
+ uintptr_t s_int;
+ uint64_t goal, before_mask, v, bits;
+ char *ret;
+
+ if (__builtin_expect (n == 0, 0))
+ {
+ /* Don't dereference any memory if the array is empty. */
+ return NULL;
+ }
+
+ /* Get an aligned pointer. */
+ s_int = (uintptr_t) s;
+ p = (const uint64_t *) (s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ will not match goal. */
+ before_mask = MASK (s_int);
+ v = (*p | before_mask) ^ (goal & before_mask);
+
+ /* Compute the address of the last byte. */
+ last_byte_ptr = (const char *) s + n - 1;
+
+ /* Compute the address of the word containing the last byte. */
+ last_word_ptr = (const uint64_t *) ((uintptr_t) last_byte_ptr & -8);
+
+ while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+ {
+ if (__builtin_expect (p == last_word_ptr, 0))
+ {
+ /* We already read the last word in the array, so give up. */
+ return NULL;
+ }
+ v = *++p;
+ }
+
+ /* We found a match, but it might be in a byte past the end
+ of the array. */
+ ret = ((char *) p) + (CFZ (bits) >> 3);
+ return (ret <= last_byte_ptr) ? ret : NULL;
+}
+weak_alias (__memchr, memchr)
+libc_hidden_builtin_def (memchr)
diff --git a/sysdeps/tile/tilegx/memcpy.c b/sysdeps/tile/tilegx/memcpy.c
new file mode 100644
index 0000000..35495be
--- /dev/null
+++ b/sysdeps/tile/tilegx/memcpy.c
@@ -0,0 +1,196 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <arch/chip.h>
+
+/* Must be 8 bytes in size. */
+#define word_t uint64_t
+
+/* How many cache lines ahead should we prefetch? */
+#define PREFETCH_LINES_AHEAD 3
+
+void *
+__memcpy (void *__restrict dstv, const void *__restrict srcv, size_t n)
+{
+ char *__restrict dst1 = (char *) dstv;
+ const char *__restrict src1 = (const char *) srcv;
+ const char *__restrict src1_end;
+ const char *__restrict prefetch;
+ word_t *__restrict dst8; /* 8-byte pointer to destination memory. */
+ word_t final; /* Final bytes to write to trailing word, if any */
+ long i;
+
+ if (n < 16)
+ {
+ for (; n; n--)
+ *dst1++ = *src1++;
+ return dstv;
+ }
+
+ /* Locate the end of source memory we will copy. Don't prefetch
+ past this. */
+ src1_end = src1 + n - 1;
+
+ /* Prefetch ahead a few cache lines, but not past the end. */
+ prefetch = src1;
+ for (i = 0; i < PREFETCH_LINES_AHEAD; i++)
+ {
+ __insn_prefetch (prefetch);
+ prefetch += CHIP_L2_LINE_SIZE ();
+ prefetch = (prefetch > src1_end) ? prefetch : src1;
+ }
+
+ /* Copy bytes until dst is word-aligned. */
+ for (; (uintptr_t) dst1 & (sizeof (word_t) - 1); n--)
+ *dst1++ = *src1++;
+
+ /* 8-byte pointer to destination memory. */
+ dst8 = (word_t *) dst1;
+
+ if (__builtin_expect ((uintptr_t) src1 & (sizeof (word_t) - 1), 0))
+ {
+ /* Misaligned copy. Copy 8 bytes at a time, but don't bother
+ with other fanciness.
+ TODO: Consider prefetching and using wh64 as well. */
+
+ /* Create an aligned src8. */
+ const word_t *__restrict src8 =
+ (const word_t *) ((uintptr_t) src1 & -sizeof (word_t));
+ word_t b;
+
+ word_t a = *src8++;
+ for (; n >= sizeof (word_t); n -= sizeof (word_t))
+ {
+ b = *src8++;
+ a = __insn_dblalign (a, b, src1);
+ *dst8++ = a;
+ a = b;
+ }
+
+ if (n == 0)
+ return dstv;
+
+ b = ((const char *) src8 <= src1_end) ? *src8 : 0;
+
+ /* Final source bytes to write to trailing partial word, if any. */
+ final = __insn_dblalign (a, b, src1);
+ }
+ else
+ {
+ /* Aligned copy. */
+
+ const word_t *__restrict src8 = (const word_t *) src1;
+
+ /* src8 and dst8 are both word-aligned. */
+ if (n >= CHIP_L2_LINE_SIZE ())
+ {
+ /* Copy until 'dst' is cache-line-aligned. */
+ for (; (uintptr_t) dst8 & (CHIP_L2_LINE_SIZE () - 1);
+ n -= sizeof (word_t))
+ *dst8++ = *src8++;
+
+ for (; n >= CHIP_L2_LINE_SIZE ();)
+ {
+ __insn_wh64 (dst8);
+
+ /* Prefetch and advance to next line to prefetch, but
+ don't go past the end. */
+ __insn_prefetch (prefetch);
+ prefetch += CHIP_L2_LINE_SIZE ();
+ prefetch = (prefetch > src1_end) ? prefetch :
+ (const char *) src8;
+
+ /* Copy an entire cache line. Manually unrolled to
+ avoid idiosyncracies of compiler unrolling. */
+#define COPY_WORD(offset) ({ dst8[offset] = src8[offset]; n -= 8; })
+ COPY_WORD (0);
+ COPY_WORD (1);
+ COPY_WORD (2);
+ COPY_WORD (3);
+ COPY_WORD (4);
+ COPY_WORD (5);
+ COPY_WORD (6);
+ COPY_WORD (7);
+#if CHIP_L2_LINE_SIZE() != 64
+# error "Fix code that assumes particular L2 cache line size."
+#endif
+
+ dst8 += CHIP_L2_LINE_SIZE () / sizeof (word_t);
+ src8 += CHIP_L2_LINE_SIZE () / sizeof (word_t);
+ }
+ }
+
+ for (; n >= sizeof (word_t); n -= sizeof (word_t))
+ *dst8++ = *src8++;
+
+ if (__builtin_expect (n == 0, 1))
+ return dstv;
+
+ final = *src8;
+ }
+
+ /* n != 0 if we get here. Write out any trailing bytes. */
+ dst1 = (char *) dst8;
+#ifndef __BIG_ENDIAN__
+ if (n & 4)
+ {
+ *(uint32_t *) dst1 = final;
+ dst1 += 4;
+ final >>= 32;
+ n &= 3;
+ }
+ if (n & 2)
+ {
+ *(uint16_t *) dst1 = final;
+ dst1 += 2;
+ final >>= 16;
+ n &= 1;
+ }
+ if (n)
+ *(uint8_t *) dst1 = final;
+#else
+ if (n & 4)
+ {
+ *(uint32_t *) dst1 = final >> 32;
+ dst1 += 4;
+ }
+ else
+ {
+ final >>= 32;
+ }
+ if (n & 2)
+ {
+ *(uint16_t *) dst1 = final >> 16;
+ dst1 += 2;
+ }
+ else
+ {
+ final >>= 16;
+ }
+ if (n & 1)
+ *(uint8_t *) dst1 = final >> 8;
+#endif
+
+ return dstv;
+}
+weak_alias (__memcpy, memcpy)
+libc_hidden_builtin_def (memcpy)
diff --git a/sysdeps/tile/tilegx/memset.c b/sysdeps/tile/tilegx/memset.c
new file mode 100644
index 0000000..ddde05f
--- /dev/null
+++ b/sysdeps/tile/tilegx/memset.c
@@ -0,0 +1,151 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <arch/chip.h>
+#include <string.h>
+#include <stdint.h>
+
+void *
+__memset (void *s, int c, size_t n)
+{
+ uint64_t *out64;
+ int n64, to_align64;
+ uint64_t v64;
+ uint8_t *out8 = s;
+
+ /* Experimentation shows that a trivial tight loop is a win up until
+ around a size of 20, where writing a word at a time starts to win. */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 7
+ /* This must be at least at least this big, or some code later
+ on doesn't work. */
+# error "BYTE_CUTOFF is too small."
+#endif
+
+ if (n < BYTE_CUTOFF)
+ {
+ /* Strangely, this turns out to be the tightest way to write
+ this loop. */
+ if (n != 0)
+ {
+ do
+ {
+ /* Strangely, combining these into one line performs worse. */
+ *out8 = c;
+ out8++;
+ }
+ while (--n != 0);
+ }
+
+ return s;
+ }
+
+ /* Align 'out8'. We know n >= 7 so this won't write past the end. */
+ while (((uintptr_t) out8 & 7) != 0)
+ {
+ *out8++ = c;
+ --n;
+ }
+
+ /* Align 'n'. */
+ while (n & 7)
+ out8[--n] = c;
+
+ out64 = (uint64_t *) out8;
+ n64 = n >> 3;
+
+ /* Tile input byte out to 64 bits. */
+ v64 = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
+
+ /* Determine how many words we need to emit before the 'out32'
+ pointer becomes aligned modulo the cache line size. */
+ to_align64 = (-((uintptr_t) out64 >> 3)) &
+ (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
+
+ /* Only bother aligning and using wh64 if there is at least
+ one full cache line to process. This check also prevents
+ overrunning the end of the buffer with alignment words. */
+ if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS)
+ {
+ int lines_left;
+
+ /* Align out64 mod the cache line size so we can use wh64. */
+ n64 -= to_align64;
+ for (; to_align64 != 0; to_align64--)
+ {
+ *out64 = v64;
+ out64++;
+ }
+
+ /* Use unsigned divide to turn this into a right shift. */
+ lines_left = (unsigned) n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+
+ do
+ {
+ /* Only wh64 a few lines at a time, so we don't exceed the
+ maximum number of victim lines. */
+ int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS ()) ? lines_left
+ : CHIP_MAX_OUTSTANDING_VICTIMS ());
+ uint64_t *wh = out64;
+ int i = x;
+ int j;
+
+ lines_left -= x;
+
+ do
+ {
+ __insn_wh64 (wh);
+ wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+ }
+ while (--i);
+
+ for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4); j != 0; j--)
+ {
+ *out64++ = v64;
+ *out64++ = v64;
+ *out64++ = v64;
+ *out64++ = v64;
+ }
+ }
+ while (lines_left != 0);
+
+ /* We processed all full lines above, so only this many
+ words remain to be processed. */
+ n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
+ }
+
+ /* Now handle any leftover values. */
+ if (n64 != 0)
+ {
+ do
+ {
+ *out64 = v64;
+ out64++;
+ }
+ while (--n64 != 0);
+ }
+
+ return s;
+}
+weak_alias (__memset, memset)
+libc_hidden_builtin_def (memset)
diff --git a/sysdeps/tile/tilegx/memusage.h b/sysdeps/tile/tilegx/memusage.h
new file mode 100644
index 0000000..7afb50a
--- /dev/null
+++ b/sysdeps/tile/tilegx/memusage.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <arch/spr_def.h>
+
+#define GETSP() ({ register uintptr_t stack_ptr asm ("sp"); stack_ptr; })
+
+#define GETTIME(low,high) \
+ { \
+ uint64_t cycles = __insn_mfspr (SPR_CYCLE); \
+ low = cycles & 0xffffffff; \
+ high = cycles >> 32; \
+ }
+
+#include <sysdeps/generic/memusage.h>
diff --git a/sysdeps/tile/tilegx/rawmemchr.c b/sysdeps/tile/tilegx/rawmemchr.c
new file mode 100644
index 0000000..cd0f2fd
--- /dev/null
+++ b/sysdeps/tile/tilegx/rawmemchr.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+void *
+__rawmemchr (const void *s, int c)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ will not match goal. */
+ const uint64_t before_mask = MASK (s_int);
+ uint64_t v = (*p | before_mask) ^ (goal & before_mask);
+
+ uint64_t bits;
+ while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+ v = *++p;
+
+ return ((char *) p) + (CFZ (bits) >> 3);
+}
+libc_hidden_def (__rawmemchr)
+weak_alias (__rawmemchr, rawmemchr)
diff --git a/sysdeps/tile/tilegx/strchr.c b/sysdeps/tile/tilegx/strchr.c
new file mode 100644
index 0000000..2dc7506
--- /dev/null
+++ b/sysdeps/tile/tilegx/strchr.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+#undef strchr
+
+char *
+strchr (const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each byte
+ is 1, and the low 7 bits are all the opposite of the goal byte). */
+ const uint64_t before_mask = MASK (s_int);
+ uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+
+ uint64_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_v1cmpeqi (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_v1cmpeq (v, goal);
+
+ if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = CFZ (zero_matches);
+ g = CFZ (goal_matches);
+
+ /* If we found c before '\0' we got a match. Note that if c == '\0'
+ then g == z, and we correctly return the address of the '\0'
+ rather than NULL. */
+ return (g <= z) ? ((char *) p) + (g >> 3) : NULL;
+}
+weak_alias (strchr, index)
+libc_hidden_builtin_def (strchr)
diff --git a/sysdeps/tile/tilegx/strchrnul.c b/sysdeps/tile/tilegx/strchrnul.c
new file mode 100644
index 0000000..bb165b5
--- /dev/null
+++ b/sysdeps/tile/tilegx/strchrnul.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+char *
+__strchrnul (const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each byte
+ is 1, and the low 7 bits are all the opposite of the goal byte). */
+ const uint64_t before_mask = MASK (s_int);
+ uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+
+ uint64_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_v1cmpeqi (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_v1cmpeq (v, goal);
+
+ if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = CFZ (zero_matches);
+ g = CFZ (goal_matches);
+
+ /* Return a pointer to the NUL or goal, whichever is first. */
+ if (z < g)
+ g = z;
+ return ((char *) p) + (g >> 3);
+}
+weak_alias (__strchrnul, strchrnul)
diff --git a/sysdeps/tile/tilegx/string-endian.h b/sysdeps/tile/tilegx/string-endian.h
new file mode 100644
index 0000000..29ca793
--- /dev/null
+++ b/sysdeps/tile/tilegx/string-endian.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Provide a mask based on the pointer alignment that
+ sets up non-zero bytes before the beginning of the string.
+ The MASK expression works because shift counts are taken mod 64.
+ Also, specify how to count "first" and "last" bits
+ when the bits have been read as a word. */
+
+#ifndef __BIG_ENDIAN__
+#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1)
+#define NULMASK(x) ((2ULL << x) - 1)
+#define CFZ(x) __insn_ctz(x)
+#define REVCZ(x) __insn_clz(x)
+#else
+#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1)))
+#define NULMASK(x) (-2LL << (63 - x))
+#define CFZ(x) __insn_clz(x)
+#define REVCZ(x) __insn_ctz(x)
+#endif
diff --git a/sysdeps/tile/tilegx/strlen.c b/sysdeps/tile/tilegx/strlen.c
new file mode 100644
index 0000000..a729e99
--- /dev/null
+++ b/sysdeps/tile/tilegx/strlen.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+size_t
+strlen (const char *s)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+ /* Read and MASK the first word. */
+ uint64_t v = *p | MASK (s_int);
+
+ uint64_t bits;
+ while ((bits = __insn_v1cmpeqi (v, 0)) == 0)
+ v = *++p;
+
+ return ((const char *) p) + (CFZ (bits) >> 3) - s;
+}
+libc_hidden_builtin_def (strlen)
diff --git a/sysdeps/tile/tilegx/strrchr.c b/sysdeps/tile/tilegx/strrchr.c
new file mode 100644
index 0000000..9724d02
--- /dev/null
+++ b/sysdeps/tile/tilegx/strrchr.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include "string-endian.h"
+
+char *
+strrchr (const char *s, int c)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *) (s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each byte
+ is 1, and the low 7 bits are all the opposite of the goal byte). */
+ const uint64_t before_mask = MASK (s_int);
+ uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+ const char *found = NULL;
+ uint64_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_v1cmpeqi (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_v1cmpeq (v, goal);
+
+ /* If we found the goal, record the last offset. */
+ if (__builtin_expect (goal_matches != 0, 0))
+ {
+ if (__builtin_expect (zero_matches != 0, 0))
+ {
+ /* Clear any goal after the first zero. */
+ int first_nul = CFZ (zero_matches);
+ goal_matches &= NULMASK (first_nul);
+ }
+ if (__builtin_expect (goal_matches != 0, 1))
+ found = ((char *) p) + 7 - (REVCZ (goal_matches) >> 3);
+ }
+
+ if (__builtin_expect (zero_matches != 0, 0))
+ return (char *) found;
+
+ v = *++p;
+ }
+}
+weak_alias (strrchr, rindex)
+libc_hidden_builtin_def (strrchr)
diff --git a/sysdeps/tile/tilegx/tilegx32/Implies b/sysdeps/tile/tilegx/tilegx32/Implies
new file mode 100644
index 0000000..993b7f4
--- /dev/null
+++ b/sysdeps/tile/tilegx/tilegx32/Implies
@@ -0,0 +1,3 @@
+tile/tilegx
+tile
+wordsize-32
diff --git a/sysdeps/tile/tilegx/tilegx64/Implies b/sysdeps/tile/tilegx/tilegx64/Implies
new file mode 100644
index 0000000..eb0686e
--- /dev/null
+++ b/sysdeps/tile/tilegx/tilegx64/Implies
@@ -0,0 +1,3 @@
+tile/tilegx
+tile
+wordsize-64
diff --git a/sysdeps/tile/tilepro/Implies b/sysdeps/tile/tilepro/Implies
new file mode 100644
index 0000000..709e1dc
--- /dev/null
+++ b/sysdeps/tile/tilepro/Implies
@@ -0,0 +1,2 @@
+tile
+wordsize-32
diff --git a/sysdeps/tile/tilepro/Makefile b/sysdeps/tile/tilepro/Makefile
new file mode 100644
index 0000000..49517fa
--- /dev/null
+++ b/sysdeps/tile/tilepro/Makefile
@@ -0,0 +1,3 @@
+ifeq ($(subdir),debug)
+sysdep_routines += tile-desc
+endif
diff --git a/sysdeps/tile/tilepro/bits/atomic.h b/sysdeps/tile/tilepro/bits/atomic.h
new file mode 100644
index 0000000..9d996cb
--- /dev/null
+++ b/sysdeps/tile/tilepro/bits/atomic.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+#include <asm/unistd.h>
+
+/* 32-bit integer compare-and-exchange. */
+static __inline __attribute__ ((always_inline))
+int __atomic_cmpxchg_32 (volatile int *mem, int newval, int oldval)
+{
+ int result;
+ __asm__ __volatile__ ("swint1"
+ : "=R00" (result), "=m" (*mem)
+ : "R10" (__NR_FAST_cmpxchg), "R00" (mem),
+ "R01" (oldval), "R02" (newval), "m" (*mem)
+ : "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29", "memory");
+ return result;
+}
+
+#define atomic_compare_and_exchange_val_acq(mem, n, o) \
+ ((__typeof (*(mem))) \
+ ((sizeof (*(mem)) == 4) ? \
+ __atomic_cmpxchg_32 ((int *) (mem), (int) (n), (int) (o)) : \
+ __atomic_error_bad_argument_size()))
+
+/* Atomically compute:
+ int old = *ptr;
+ *ptr = (old & mask) + addend;
+ return old; */
+
+static __inline __attribute__ ((always_inline))
+int __atomic_update_32 (volatile int *mem, int mask, int addend)
+{
+ int result;
+ __asm__ __volatile__ ("swint1"
+ : "=R00" (result), "=m" (*mem)
+ : "R10" (__NR_FAST_atomic_update), "R00" (mem),
+ "R01" (mask), "R02" (addend), "m" (*mem)
+ : "r20", "r21", "r22", "r23", "r24",
+ "r25", "r26", "r27", "r28", "r29", "memory");
+ return result;
+}
+
+/* Size-checked verson of __atomic_update_32. */
+#define __atomic_update(mem, mask, addend) \
+ ((__typeof (*(mem))) \
+ ((sizeof (*(mem)) == 4) ? \
+ __atomic_update_32 ((int *) (mem), (int) (mask), (int) (addend)) : \
+ __atomic_error_bad_argument_size ()))
+
+#define atomic_exchange_acq(mem, newvalue) \
+ __atomic_update ((mem), 0, (newvalue))
+#define atomic_exchange_and_add(mem, value) \
+ __atomic_update ((mem), -1, (value))
+#define atomic_and_val(mem, mask) \
+ __atomic_update ((mem), (mask), 0)
+#define atomic_or_val(mem, mask) \
+ ({ __typeof (mask) __att1_v = (mask); \
+ __atomic_update ((mem), ~__att1_v, __att1_v); })
+
+#include <sysdeps/tile/bits/atomic.h>
+
+#endif /* bits/atomic.h */
diff --git a/sysdeps/tile/tilepro/bits/wordsize.h b/sysdeps/tile/tilepro/bits/wordsize.h
new file mode 100644
index 0000000..da587a2
--- /dev/null
+++ b/sysdeps/tile/tilepro/bits/wordsize.h
@@ -0,0 +1,3 @@
+/* Determine the wordsize from the preprocessor defines. */
+
+#define __WORDSIZE 32
diff --git a/sysdeps/tile/tilepro/memchr.c b/sysdeps/tile/tilepro/memchr.c
new file mode 100644
index 0000000..125fd0d
--- /dev/null
+++ b/sysdeps/tile/tilepro/memchr.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+void *
+__memchr (const void *s, int c, size_t n)
+{
+ const uint32_t *last_word_ptr;
+ const uint32_t *p;
+ const char *last_byte_ptr;
+ uintptr_t s_int;
+ uint32_t goal, before_mask, v, bits;
+ char *ret;
+
+ if (__builtin_expect (n == 0, 0))
+ {
+ /* Don't dereference any memory if the array is empty. */
+ return NULL;
+ }
+
+ /* Get an aligned pointer. */
+ s_int = (uintptr_t) s;
+ p = (const uint32_t *) (s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ will not match goal. Note that this shift count expression works
+ because we know shift counts are taken mod 32. */
+ before_mask = (1 << (s_int << 3)) - 1;
+ v = (*p | before_mask) ^ (goal & before_mask);
+
+ /* Compute the address of the last byte. */
+ last_byte_ptr = (const char *) s + n - 1;
+
+ /* Compute the address of the word containing the last byte. */
+ last_word_ptr = (const uint32_t *) ((uintptr_t) last_byte_ptr & -4);
+
+ while ((bits = __insn_seqb (v, goal)) == 0)
+ {
+ if (__builtin_expect (p == last_word_ptr, 0))
+ {
+ /* We already read the last word in the array, so give up. */
+ return NULL;
+ }
+ v = *++p;
+ }
+
+ /* We found a match, but it might be in a byte past the end of the array. */
+ ret = ((char *) p) + (__insn_ctz (bits) >> 3);
+ return (ret <= last_byte_ptr) ? ret : NULL;
+}
+weak_alias (__memchr, memchr)
+libc_hidden_builtin_def (memchr)
diff --git a/sysdeps/tile/tilepro/memcpy.S b/sysdeps/tile/tilepro/memcpy.S
new file mode 100644
index 0000000..f481103
--- /dev/null
+++ b/sysdeps/tile/tilepro/memcpy.S
@@ -0,0 +1,399 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <arch/chip.h>
+#include <feedback-asm.h>
+#include <sysdep.h>
+
+ .text
+ENTRY (__memcpy)
+ FEEDBACK_ENTER(__memcpy)
+
+ /* r0 is the dest, r1 is the source, r2 is the size. */
+
+ /* Save aside original dest so we can return it at the end. */
+ { sw sp, lr; move r23, r0; or r4, r0, r1 }
+ cfi_offset (lr, 0)
+
+ /* Check for an empty size. */
+ { bz r2, .Ldone; andi r4, r4, 3 }
+
+ /* Check for an unaligned source or dest. */
+ { bnz r4, .Lcopy_unaligned_maybe_many; addli r4, r2, -256 }
+
+.Lcheck_aligned_copy_size:
+ /* If we are copying < 256 bytes, branch to simple case. */
+ { blzt r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+
+ /* Copying >= 256 bytes, so jump to complex prefetching loop. */
+ { andi r6, r1, 63; j .Lcopy_many }
+
+/* Aligned 4 byte at a time copy loop. */
+
+.Lcopy_8_loop:
+ /* Copy two words at a time to hide load latency. */
+ { lw r3, r1; addi r1, r1, 4; slti_u r8, r2, 16 }
+ { lw r4, r1; addi r1, r1, 4 }
+ { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+ { sw r0, r4; addi r0, r0, 4; addi r2, r2, -4 }
+.Lcopy_8_check:
+ { bzt r8, .Lcopy_8_loop; slti_u r4, r2, 4 }
+
+ /* Copy odd leftover word, if any. */
+ { bnzt r4, .Lcheck_odd_stragglers }
+ { lw r3, r1; addi r1, r1, 4 }
+ { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+
+.Lcheck_odd_stragglers:
+ { bnz r2, .Lcopy_unaligned_few }
+
+.Ldone:
+ { move r0, r23; jrp lr }
+
+/* Prefetching multiple cache line copy handler (for large transfers). */
+
+ /* Copy words until r1 is cache-line-aligned. */
+.Lalign_loop:
+ { lw r3, r1; addi r1, r1, 4 }
+ { andi r6, r1, 63 }
+ { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+.Lcopy_many:
+ { bnzt r6, .Lalign_loop; addi r9, r0, 63 }
+
+ { addi r3, r1, 60; andi r9, r9, -64 }
+
+ /* No need to prefetch dst, we'll just do the wh64
+ right before we copy a line. */
+ { lw r5, r3; addi r3, r3, 64; movei r4, 1 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, .; move r27, lr }
+ { lw r6, r3; addi r3, r3, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ { lw r7, r3; addi r3, r3, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bz zero, .Lbig_loop2 }
+
+ /* On entry to this loop:
+ - r0 points to the start of dst line 0
+ - r1 points to start of src line 0
+ - r2 >= (256 - 60), only the first time the loop trips.
+ - r3 contains r1 + 128 + 60 [pointer to end of source line 2]
+ This is our prefetch address. When we get near the end
+ rather than prefetching off the end this is changed to point
+ to some "safe" recently loaded address.
+ - r5 contains *(r1 + 60) [i.e. last word of source line 0]
+ - r6 contains *(r1 + 64 + 60) [i.e. last word of source line 1]
+ - r9 contains ((r0 + 63) & -64)
+ [start of next dst cache line.] */
+
+.Lbig_loop:
+ { jal .Lcopy_line2; add r15, r1, r2 }
+
+.Lbig_loop2:
+ /* Copy line 0, first stalling until r5 is ready. */
+ { move r12, r5; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+ { lw r5, r3; addi r3, r3, 64 }
+ { jal .Lcopy_line }
+
+ /* Copy line 1, first stalling until r6 is ready. */
+ { move r12, r6; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+ { lw r6, r3; addi r3, r3, 64 }
+ { jal .Lcopy_line }
+
+ /* Copy line 2, first stalling until r7 is ready. */
+ { move r12, r7; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+ { lw r7, r3; addi r3, r3, 64 }
+ /* Use up a caches-busy cycle by jumping back to the top of the
+ loop. Might as well get it out of the way now. */
+ { j .Lbig_loop }
+
+
+ /* On entry:
+ - r0 points to the destination line.
+ - r1 points to the source line.
+ - r3 is the next prefetch address.
+ - r9 holds the last address used for wh64.
+ - r12 = WORD_15
+ - r16 = WORD_0.
+ - r17 == r1 + 16.
+ - r27 holds saved lr to restore.
+
+ On exit:
+ - r0 is incremented by 64.
+ - r1 is incremented by 64, unless that would point to a word
+ beyond the end of the source array, in which case it is redirected
+ to point to an arbitrary word already in the cache.
+ - r2 is decremented by 64.
+ - r3 is unchanged, unless it points to a word beyond the
+ end of the source array, in which case it is redirected
+ to point to an arbitrary word already in the cache.
+ Redirecting is OK since if we are that close to the end
+ of the array we will not come back to this subroutine
+ and use the contents of the prefetched address.
+ - r4 is nonzero iff r2 >= 64.
+ - r9 is incremented by 64, unless it points beyond the
+ end of the last full destination cache line, in which
+ case it is redirected to a "safe address" that can be
+ clobbered (sp - 64)
+ - lr contains the value in r27. */
+
+/* r26 unused */
+
+.Lcopy_line:
+ /* TODO: when r3 goes past the end, we would like to redirect it
+ to prefetch the last partial cache line (if any) just once, for the
+ benefit of the final cleanup loop. But we don't want to
+ prefetch that line more than once, or subsequent prefetches
+ will go into the RTF. But then .Lbig_loop should unconditionally
+ branch to top of loop to execute final prefetch, and its
+ nop should become a conditional branch. */
+
+ /* We need two non-memory cycles here to cover the resources
+ used by the loads initiated by the caller. */
+ { add r15, r1, r2 }
+.Lcopy_line2:
+ { slt_u r13, r3, r15; addi r17, r1, 16 }
+
+ /* NOTE: this will stall for one cycle as L1 is busy. */
+
+ /* Fill second L1D line. */
+ { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */
+
+ /* Prepare destination line for writing. */
+ { wh64 r9; addi r9, r9, 64 }
+
+ /* Load seven words that are L1D hits to cover wh64 L2 usage. */
+
+ /* Load the three remaining words from the last L1D line, which
+ we know has already filled the L1D. */
+ { lw r4, r1; addi r1, r1, 4; addi r20, r1, 16 } /* r4 = WORD_12 */
+ { lw r8, r1; addi r1, r1, 4; slt_u r13, r20, r15 }/* r8 = WORD_13 */
+ { lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 } /* r11 = WORD_14 */
+
+ /* Load the three remaining words from the first L1D line, first
+ stalling until it has filled by "looking at" r16. */
+ { lw r13, r1; addi r1, r1, 4; move zero, r16 } /* r13 = WORD_1 */
+ { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_2 */
+ { lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */
+
+ /* Load second word from the second L1D line, first
+ stalling until it has filled by "looking at" r17. */
+ { lw r19, r1; addi r1, r1, 4; move zero, r17 } /* r19 = WORD_5 */
+
+ /* Store last word to the destination line, potentially dirtying it
+ for the first time, which keeps the L2 busy for two cycles. */
+ { sw r10, r12 } /* store(WORD_15) */
+
+ /* Use two L1D hits to cover the sw L2 access above. */
+ { lw r10, r1; addi r1, r1, 4 } /* r10 = WORD_6 */
+ { lw r12, r1; addi r1, r1, 4 } /* r12 = WORD_7 */
+
+ /* Fill third L1D line. */
+ { lw r18, r1; addi r1, r1, 4 } /* r18 = WORD_8 */
+
+ /* Store first L1D line. */
+ { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */
+ { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */
+ { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */
+ { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */
+
+ /* Store second L1D line. */
+ { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */
+ { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */
+ { sw r0, r10; addi r0, r0, 4 } /* store(WORD_6) */
+ { sw r0, r12; addi r0, r0, 4 } /* store(WORD_7) */
+
+ { lw r13, r1; addi r1, r1, 4; move zero, r18 } /* r13 = WORD_9 */
+ { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_10 */
+ { lw r15, r1; move r1, r20 } /* r15 = WORD_11 */
+
+ /* Store third L1D line. */
+ { sw r0, r18; addi r0, r0, 4 } /* store(WORD_8) */
+ { sw r0, r13; addi r0, r0, 4 } /* store(WORD_9) */
+ { sw r0, r14; addi r0, r0, 4 } /* store(WORD_10) */
+ { sw r0, r15; addi r0, r0, 4 } /* store(WORD_11) */
+
+ /* Store rest of fourth L1D line. */
+ { sw r0, r4; addi r0, r0, 4 } /* store(WORD_12) */
+ {
+ sw r0, r8 /* store(WORD_13) */
+ addi r0, r0, 4
+ /* Will r2 be > 64 after we subtract 64 below? */
+ shri r4, r2, 7
+ }
+ {
+ sw r0, r11 /* store(WORD_14) */
+ addi r0, r0, 8
+ /* Record 64 bytes successfully copied. */
+ addi r2, r2, -64
+ }
+
+ { jrp lr; move lr, r27 }
+
+ /* Convey to the backtrace library that the stack frame is
+ size zero, and the real return address is on the stack
+ rather than in 'lr'. */
+ { info 8 }
+
+ .align 64
+.Lcopy_unaligned_maybe_many:
+ /* Skip the setup overhead if we aren't copying many bytes. */
+ { slti_u r8, r2, 20; sub r4, zero, r0 }
+ { bnzt r8, .Lcopy_unaligned_few; andi r4, r4, 3 }
+ { bz r4, .Ldest_is_word_aligned; add r18, r1, r2 }
+
+/* Unaligned 4 byte at a time copy handler. */
+
+ /* Copy single bytes until r0 == 0 mod 4, so we can store words. */
+.Lalign_dest_loop:
+ { lb_u r3, r1; addi r1, r1, 1; addi r4, r4, -1 }
+ { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r4, .Lalign_dest_loop; andi r3, r1, 3 }
+
+ /* If source and dest are now *both* aligned, do an aligned copy. */
+ { bz r3, .Lcheck_aligned_copy_size; addli r4, r2, -256 }
+
+.Ldest_is_word_aligned:
+
+ { andi r8, r0, 63; lwadd_na r6, r1, 4}
+ { slti_u r9, r2, 64; bz r8, .Ldest_is_L2_line_aligned }
+
+ /* This copies unaligned words until either there are fewer
+ than 4 bytes left to copy, or until the destination pointer
+ is cache-aligned, whichever comes first.
+
+ On entry:
+ - r0 is the next store address.
+ - r1 points 4 bytes past the load address corresponding to r0.
+ - r2 >= 4
+ - r6 is the next aligned word loaded. */
+.Lcopy_unaligned_src_words:
+ { lwadd_na r7, r1, 4; slti_u r8, r2, 4 + 4 }
+ /* stall */
+ { dword_align r6, r7, r1; slti_u r9, r2, 64 + 4 }
+ { swadd r0, r6, 4; addi r2, r2, -4 }
+ { bnz r8, .Lcleanup_unaligned_words; andi r8, r0, 63 }
+ { bnzt r8, .Lcopy_unaligned_src_words; move r6, r7 }
+
+ /* On entry:
+ - r0 is the next store address.
+ - r1 points 4 bytes past the load address corresponding to r0.
+ - r2 >= 4 (# of bytes left to store).
+ - r6 is the next aligned src word value.
+ - r9 = (r2 < 64U).
+ - r18 points one byte past the end of source memory. */
+.Ldest_is_L2_line_aligned:
+
+ {
+ /* Not a full cache line remains. */
+ bnz r9, .Lcleanup_unaligned_words
+ move r7, r6
+ }
+
+ /* r2 >= 64 */
+
+ /* Kick off two prefetches, but don't go past the end. */
+ { addi r3, r1, 63 - 4; addi r8, r1, 64 + 63 - 4 }
+ { prefetch r3; move r3, r8; slt_u r8, r8, r18 }
+ { mvz r3, r8, r1; addi r8, r3, 64 }
+ { prefetch r3; move r3, r8; slt_u r8, r8, r18 }
+ { mvz r3, r8, r1; movei r17, 0 }
+
+.Lcopy_unaligned_line:
+ /* Prefetch another line. */
+ { prefetch r3; addi r15, r1, 60; addi r3, r3, 64 }
+ /* Fire off a load of the last word we are about to copy. */
+ { lw_na r15, r15; slt_u r8, r3, r18 }
+
+ { mvz r3, r8, r1; wh64 r0 }
+
+ /* This loop runs twice.
+
+ On entry:
+ - r17 is even before the first iteration, and odd before
+ the second. It is incremented inside the loop. Encountering
+ an even value at the end of the loop makes it stop. */
+.Lcopy_half_an_unaligned_line:
+ {
+ /* Stall until the last byte is ready. In the steady state this
+ guarantees all words to load below will be in the L2 cache, which
+ avoids shunting the loads to the RTF. */
+ move zero, r15
+ lwadd_na r7, r1, 16
+ }
+ { lwadd_na r11, r1, 12 }
+ { lwadd_na r14, r1, -24 }
+ { lwadd_na r8, r1, 4 }
+ { lwadd_na r9, r1, 4 }
+ {
+ lwadd_na r10, r1, 8
+ /* r16 = (r2 < 64), after we subtract 32 from r2 below. */
+ slti_u r16, r2, 64 + 32
+ }
+ { lwadd_na r12, r1, 4; addi r17, r17, 1 }
+ { lwadd_na r13, r1, 8; dword_align r6, r7, r1 }
+ { swadd r0, r6, 4; dword_align r7, r8, r1 }
+ { swadd r0, r7, 4; dword_align r8, r9, r1 }
+ { swadd r0, r8, 4; dword_align r9, r10, r1 }
+ { swadd r0, r9, 4; dword_align r10, r11, r1 }
+ { swadd r0, r10, 4; dword_align r11, r12, r1 }
+ { swadd r0, r11, 4; dword_align r12, r13, r1 }
+ { swadd r0, r12, 4; dword_align r13, r14, r1 }
+ { swadd r0, r13, 4; addi r2, r2, -32 }
+ { move r6, r14; bbst r17, .Lcopy_half_an_unaligned_line }
+
+ { bzt r16, .Lcopy_unaligned_line; move r7, r6 }
+
+ /* On entry:
+ - r0 is the next store address.
+ - r1 points 4 bytes past the load address corresponding to r0.
+ - r2 >= 0 (# of bytes left to store).
+ - r7 is the next aligned src word value. */
+.Lcleanup_unaligned_words:
+ /* Handle any trailing bytes. */
+ { bz r2, .Lcopy_unaligned_done; slti_u r8, r2, 4 }
+ { bzt r8, .Lcopy_unaligned_src_words; move r6, r7 }
+
+ /* Move r1 back to the point where it corresponds to r0. */
+ { addi r1, r1, -4 }
+
+ /* Fall through */
+
+/* 1 byte at a time copy handler. */
+
+.Lcopy_unaligned_few:
+ { lb_u r3, r1; addi r1, r1, 1 }
+ { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r2, .Lcopy_unaligned_few }
+
+.Lcopy_unaligned_done:
+
+ { move r0, r23; jrp lr }
+
+END (__memcpy)
+
+weak_alias (__memcpy, memcpy)
+libc_hidden_builtin_def (memcpy)
diff --git a/sysdeps/tile/tilepro/memset.c b/sysdeps/tile/tilepro/memset.c
new file mode 100644
index 0000000..bfdc3d4
--- /dev/null
+++ b/sysdeps/tile/tilepro/memset.c
@@ -0,0 +1,152 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+#include <arch/chip.h>
+
+void *
+__memset (void *s, int c, size_t n)
+{
+ uint32_t *out32;
+ int n32;
+ uint32_t v16, v32;
+ uint8_t *out8 = s;
+ int to_align32;
+
+ /* Experimentation shows that a trivial tight loop is a win up until
+ around a size of 20, where writing a word at a time starts to win. */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 3
+ /* This must be at least at least this big, or some code later
+ on doesn't work. */
+# error "BYTE_CUTOFF is too small."
+#endif
+
+ if (n < BYTE_CUTOFF)
+ {
+ /* Strangely, this turns out to be the tightest way to write
+ this loop. */
+ if (n != 0)
+ {
+ do
+ {
+ /* Strangely, combining these into one line performs worse. */
+ *out8 = c;
+ out8++;
+ }
+ while (--n != 0);
+ }
+
+ return s;
+ }
+
+ /* Align 'out8'. We know n >= 3 so this won't write past the end. */
+ while (((uintptr_t) out8 & 3) != 0)
+ {
+ *out8++ = c;
+ --n;
+ }
+
+ /* Align 'n'. */
+ while (n & 3)
+ out8[--n] = c;
+
+ out32 = (uint32_t *) out8;
+ n32 = n >> 2;
+
+ /* Tile input byte out to 32 bits. */
+ v16 = __insn_intlb (c, c);
+ v32 = __insn_intlh (v16, v16);
+
+ /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_WORDS (CHIP_L2_LINE_SIZE() / 4)
+
+ /* Determine how many words we need to emit before the 'out32'
+ pointer becomes aligned modulo the cache line size. */
+ to_align32 = (-((uintptr_t) out32 >> 2)) & (CACHE_LINE_SIZE_IN_WORDS - 1);
+
+ /* Only bother aligning and using wh64 if there is at least one full
+ cache line to process. This check also prevents overrunning the
+ end of the buffer with alignment words. */
+ if (to_align32 <= n32 - CACHE_LINE_SIZE_IN_WORDS)
+ {
+ int lines_left;
+
+ /* Align out32 mod the cache line size so we can use wh64. */
+ n32 -= to_align32;
+ for (; to_align32 != 0; to_align32--)
+ {
+ *out32 = v32;
+ out32++;
+ }
+
+ /* Use unsigned divide to turn this into a right shift. */
+ lines_left = (unsigned) n32 / CACHE_LINE_SIZE_IN_WORDS;
+
+ do
+ {
+ /* Only wh64 a few lines at a time, so we don't exceed the
+ maximum number of victim lines. */
+ int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS ())? lines_left
+ : CHIP_MAX_OUTSTANDING_VICTIMS ());
+ uint32_t *wh = out32;
+ int i = x;
+ int j;
+
+ lines_left -= x;
+
+ do
+ {
+ __insn_wh64 (wh);
+ wh += CACHE_LINE_SIZE_IN_WORDS;
+ }
+ while (--i);
+
+ for (j = x * (CACHE_LINE_SIZE_IN_WORDS / 4); j != 0; j--)
+ {
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ }
+ }
+ while (lines_left != 0);
+
+ /* We processed all full lines above, so only this many words
+ remain to be processed. */
+ n32 &= CACHE_LINE_SIZE_IN_WORDS - 1;
+ }
+
+ /* Now handle any leftover values. */
+ if (n32 != 0)
+ {
+ do
+ {
+ *out32 = v32;
+ out32++;
+ }
+ while (--n32 != 0);
+ }
+
+ return s;
+}
+weak_alias (__memset, memset)
+libc_hidden_builtin_def (memset)
diff --git a/sysdeps/tile/tilepro/memusage.h b/sysdeps/tile/tilepro/memusage.h
new file mode 100644
index 0000000..700c08b
--- /dev/null
+++ b/sysdeps/tile/tilepro/memusage.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <arch/spr_def.h>
+
+#define GETSP() ({ register uintptr_t stack_ptr asm ("sp"); stack_ptr; })
+
+#define GETTIME(low,high) \
+ { \
+ low = __insn_mfspr (SPR_CYCLE_LOW); \
+ high = __insn_mfspr (SPR_CYCLE_HIGH); \
+ }
+
+#include <sysdeps/generic/memusage.h>
diff --git a/sysdeps/tile/tilepro/rawmemchr.c b/sysdeps/tile/tilepro/rawmemchr.c
new file mode 100644
index 0000000..c1a58ec
--- /dev/null
+++ b/sysdeps/tile/tilepro/rawmemchr.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+void *
+__rawmemchr (const void *s, int c)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *) (s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ will not match goal. Note that this shift count expression works
+ because we know shift counts are taken mod 32. */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & before_mask);
+
+ uint32_t bits;
+ while ((bits = __insn_seqb (v, goal)) == 0)
+ v = *++p;
+
+ return ((char *) p) + (__insn_ctz (bits) >> 3);
+}
+libc_hidden_def (__rawmemchr)
+weak_alias (__rawmemchr, rawmemchr)
diff --git a/sysdeps/tile/tilepro/strchr.c b/sysdeps/tile/tilepro/strchr.c
new file mode 100644
index 0000000..e116ea9
--- /dev/null
+++ b/sysdeps/tile/tilepro/strchr.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+#undef strchr
+
+char *
+strchr (const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *) (s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each
+ byte is 1, and the low 7 bits are all the opposite of the goal
+ byte). Note that this shift count expression works because we
+ know shift counts are taken mod 32. */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & __insn_shrib (before_mask, 1));
+
+ uint32_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_seqb (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_seqb (v, goal);
+
+ if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = __insn_ctz (zero_matches);
+ g = __insn_ctz (goal_matches);
+
+ /* If we found c before '\0' we got a match. Note that if c == '\0'
+ then g == z, and we correctly return the address of the '\0'
+ rather than NULL. */
+ return (g <= z) ? ((char *) p) + (g >> 3) : NULL;
+}
+weak_alias (strchr, index)
+libc_hidden_builtin_def (strchr)
diff --git a/sysdeps/tile/tilepro/strchrnul.c b/sysdeps/tile/tilepro/strchrnul.c
new file mode 100644
index 0000000..6e7bba9
--- /dev/null
+++ b/sysdeps/tile/tilepro/strchrnul.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+char *
+__strchrnul (const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *) (s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each
+ byte is 1, and the low 7 bits are all the opposite of the goal
+ byte). Note that this shift count expression works because we
+ know shift counts are taken mod 32. */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & __insn_shrib (before_mask, 1));
+
+ uint32_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_seqb (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_seqb (v, goal);
+
+ if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = __insn_ctz (zero_matches);
+ g = __insn_ctz (goal_matches);
+
+ /* Return a pointer to the NUL or goal, whichever is first. */
+ if (z < g)
+ g = z;
+ return ((char *) p) + (g >> 3);
+}
+weak_alias (__strchrnul, strchrnul)
diff --git a/sysdeps/tile/tilepro/strlen.c b/sysdeps/tile/tilepro/strlen.c
new file mode 100644
index 0000000..2612068
--- /dev/null
+++ b/sysdeps/tile/tilepro/strlen.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+size_t
+strlen (const char *s)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *) (s_int & -4);
+
+ /* Read the first word, but force bytes before the string to be nonzero.
+ This expression works because we know shift counts are taken mod 32. */
+ uint32_t v = *p | ((1 << (s_int << 3)) - 1);
+
+ uint32_t bits;
+ while ((bits = __insn_seqb (v, 0)) == 0)
+ v = *++p;
+
+ return ((const char *) p) + (__insn_ctz (bits) >> 3) - s;
+}
+libc_hidden_builtin_def (strlen)
diff --git a/sysdeps/tile/tilepro/strrchr.c b/sysdeps/tile/tilepro/strrchr.c
new file mode 100644
index 0000000..b91b02b
--- /dev/null
+++ b/sysdeps/tile/tilepro/strrchr.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <string.h>
+#include <stdint.h>
+
+char *
+strrchr (const char *s, int c)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *) (s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ match neither zero nor goal (we make sure the high bit of each
+ byte is 1, and the low 7 bits are all the opposite of the goal
+ byte). Note that this shift count expression works because we
+ know shift counts are taken mod 32. */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & __insn_shrib (before_mask, 1));
+ const char *found = NULL;
+ uint32_t zero_matches, goal_matches;
+ while (1)
+ {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_seqb (v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_seqb (v, goal);
+
+ /* If we found the goal, record the last offset. */
+ if (__builtin_expect (goal_matches != 0, 0))
+ {
+ if (__builtin_expect (zero_matches != 0, 0))
+ {
+ /* Clear any goal after the first zero. */
+ int first_nul = __insn_ctz (zero_matches);
+ /* The number of top bits we need to clear is
+ 32 - (first_nul + 8). */
+ int shift_amt = (24 - first_nul);
+ goal_matches <<= shift_amt;
+ goal_matches >>= shift_amt;
+ }
+ if (__builtin_expect (goal_matches != 0, 1))
+ found = ((char *) p) + 3 - (__insn_clz (goal_matches) >> 3);
+ }
+
+ if (__builtin_expect (zero_matches != 0, 0))
+ return (char *) found;
+
+ v = *++p;
+ }
+}
+weak_alias (strrchr, rindex)
+libc_hidden_builtin_def (strrchr)
diff --git a/sysdeps/tile/tls-macros.h b/sysdeps/tile/tls-macros.h
new file mode 100644
index 0000000..88023bc
--- /dev/null
+++ b/sysdeps/tile/tls-macros.h
@@ -0,0 +1,50 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef __tilegx__
+#define TLS_GD_REL "hw0_last_tls_gd"
+#define TLS_IE_REL "hw0_last_tls_ie"
+#else
+#define TLS_GD_REL "tls_gd_lo16"
+#define TLS_IE_REL "tls_ie_lo16"
+#endif
+
+#define TLS_GD(x) \
+ ({ \
+ int __offset; \
+ extern char _GLOBAL_OFFSET_TABLE_[]; \
+ extern void *__tls_get_addr (void *); \
+ \
+ asm ("moveli %0, " TLS_GD_REL "(" #x ")" : "=&r" (__offset)); \
+ (int *) __tls_get_addr (_GLOBAL_OFFSET_TABLE_ + __offset); })
+
+/* No special support for LD mode. */
+#define TLS_LD TLS_GD
+
+#define TLS_IE(x) \
+ ({ \
+ register char *__tp asm("tp"); \
+ extern char _GLOBAL_OFFSET_TABLE_[]; \
+ int __offset; \
+ \
+ asm ("moveli %0, " TLS_IE_REL "(" #x ")" : "=&r" (__offset)); \
+ (int *) (__tp + *(int *) (_GLOBAL_OFFSET_TABLE_ + __offset)); })
+
+/* No special support for LE mode. */
+#define TLS_LE TLS_IE
diff --git a/sysdeps/tile/tst-audit.h b/sysdeps/tile/tst-audit.h
new file mode 100644
index 0000000..d0e24f2
--- /dev/null
+++ b/sysdeps/tile/tst-audit.h
@@ -0,0 +1,26 @@
+/* Definitions for testing PLT entry/exit auditing. ARM version.
+
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define pltenter la_tile_gnu_pltenter
+#define pltexit la_tile_gnu_pltexit
+#define La_regs La_tile_regs
+#define La_retval La_tile_retval
+#define int_retval lrv_reg[0]