diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-07-12 18:26:36 +0000 |
commit | 0ecb606cb6cf65de1d9fc8a919bceb4be476c602 (patch) | |
tree | 2ea1f8305970753e4a657acb2ccc15ca3eec8e2c /sysdeps/s390/s390-32 | |
parent | 7d58530341304d403a6626d7f7a1913165fe2f32 (diff) | |
download | glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.gz glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.tar.xz glibc-0ecb606cb6cf65de1d9fc8a919bceb4be476c602.zip |
2.5-18.1
Diffstat (limited to 'sysdeps/s390/s390-32')
-rw-r--r-- | sysdeps/s390/s390-32/Dist | 1 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/__longjmp.c | 36 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/backtrace.c | 5 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/bits/wordsize.h | 11 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/dl-machine.h | 151 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/dl-trampoline.S | 134 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/elf/setjmp.S | 17 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/elf/start.S | 9 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/s390-mcount.S | 2 | ||||
-rw-r--r-- | sysdeps/s390/s390-32/setjmp.S | 17 |
10 files changed, 227 insertions, 156 deletions
diff --git a/sysdeps/s390/s390-32/Dist b/sysdeps/s390/s390-32/Dist deleted file mode 100644 index 1cd482830a..0000000000 --- a/sysdeps/s390/s390-32/Dist +++ /dev/null @@ -1 +0,0 @@ -s390-mcount.S diff --git a/sysdeps/s390/s390-32/__longjmp.c b/sysdeps/s390/s390-32/__longjmp.c index c1b977cd49..c47ebbc52a 100644 --- a/sysdeps/s390/s390-32/__longjmp.c +++ b/sysdeps/s390/s390-32/__longjmp.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). @@ -29,14 +29,32 @@ void __longjmp (__jmp_buf env, int val) { - /* Restore registers and jump back. */ - asm volatile ("lr %%r2,%0\n\t" /* PUT val in grp 2. */ - "ld %%f6,48(%1)\n\t" - "ld %%f4,40(%1)\n\t" - "lm %%r6,%%r15,0(%1)\n\t" - "br %%r14" - : : "r" (val == 0 ? 1 : val), - "a" (env) : "2" ); + register int r2 __asm ("%r2") = val == 0 ? 1 : val; +#ifdef PTR_DEMANGLE + register uintptr_t r3 __asm ("%r3") = THREAD_GET_POINTER_GUARD (); + register void *r1 __asm ("%r1") = (void *) env; +#endif + /* Restore registers and jump back. */ + asm volatile ("ld %%f6,48(%1)\n\t" + "ld %%f4,40(%1)\n\t" +#ifdef PTR_DEMANGLE + "lm %%r6,%%r13,0(%1)\n\t" + "lm %%r4,%%r5,32(%1)\n\t" + "xr %%r4,%2\n\t" + "xr %%r5,%2\n\t" + "lr %%r15,%%r5\n\t" + "br %%r4" +#else + "lm %%r6,%%r15,0(%1)\n\t" + "br %%r14" +#endif + : : "r" (r2), +#ifdef PTR_DEMANGLE + "r" (r1), "r" (r3) +#else + "a" (env) +#endif + ); /* Avoid `volatile function does return' warnings. */ for (;;); diff --git a/sysdeps/s390/s390-32/backtrace.c b/sysdeps/s390/s390-32/backtrace.c index 7a632572b5..6adc3bc3d1 100644 --- a/sysdeps/s390/s390-32/backtrace.c +++ b/sysdeps/s390/s390-32/backtrace.c @@ -1,6 +1,6 @@ /* Return backtrace of current program state. - Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc. - Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). + Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -142,3 +142,4 @@ __backtrace (void **array, int size) } weak_alias (__backtrace, backtrace) +libc_hidden_def (__backtrace) diff --git a/sysdeps/s390/s390-32/bits/wordsize.h b/sysdeps/s390/s390-32/bits/wordsize.h index 4f50d8586c..b41661217f 100644 --- a/sysdeps/s390/s390-32/bits/wordsize.h +++ b/sysdeps/s390/s390-32/bits/wordsize.h @@ -5,3 +5,14 @@ #else # define __WORDSIZE 32 #endif + +#if !defined __NO_LONG_DOUBLE_MATH && !defined __LONG_DOUBLE_MATH_OPTIONAL + +/* Signal that we didn't used to have a `long double'. The changes all + the `long double' function variants to be redirects to the double + functions. */ +# define __LONG_DOUBLE_MATH_OPTIONAL 1 +# ifndef __LONG_DOUBLE_128__ +# define __NO_LONG_DOUBLE_MATH 1 +# endif +#endif diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h index 52922a813b..8bbf858fbf 100644 --- a/sysdeps/s390/s390-32/dl-machine.h +++ b/sysdeps/s390/s390-32/dl-machine.h @@ -1,5 +1,6 @@ /* Machine-dependent ELF dynamic relocation inline functions. S390 Version. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. Contributed by Carl Pederson & Martin Schwidefsky. This file is part of the GNU C Library. @@ -21,7 +22,6 @@ #ifndef dl_machine_h #define dl_machine_h - #define ELF_MACHINE_NAME "s390" #include <sys/param.h> @@ -112,7 +112,8 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) { got[2] = (Elf32_Addr) &_dl_runtime_profile; - if (_dl_name_match_p (GLRO(dl_profile), l)) + 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; @@ -126,124 +127,6 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) return lazy; } -/* This code is used in dl-runtime.c to call the `fixup' function - and then redirect to the address it returns. */ - -/* s390: - Arguments are in register. - r2 - r7 holds the original parameters for the function call, fixup - and trampoline code use r0-r5 and r14-15. For the correct function - call r2-r5 and r14-15 must be restored. - Arguments from the PLT are stored at 24(r15) and 28(r15) - and must be moved to r2 and r3 for the fixup call (see elf32-s390.c - in the binutils for the PLT code). - Fixup function address in r2. -*/ -#ifndef PROF -#define ELF_MACHINE_RUNTIME_TRAMPOLINE \ - asm ( "\ - .text\n\ - .globl _dl_runtime_resolve\n\ - .type _dl_runtime_resolve, @function\n\ - .align 16\n\ - " CFI_STARTPROC "\n\ -_dl_runtime_resolve:\n\ - # save registers\n\ - stm 2,5,32(15)\n\ - st 14,48(15)\n\ - lr 0,15\n\ - ahi 15,-96\n\ - " CFI_ADJUST_CFA_OFFSET(96)"\n\ - st 0,0(15)\n\ - # load args saved by PLT\n\ - lm 2,3,120(15)\n\ - basr 1,0\n\ -0: ahi 1,1f-0b\n\ - l 14,0(1)\n\ - bas 14,0(14,1) # call fixup\n\ - lr 1,2 # function addr returned in r2\n\ - # restore registers\n\ - ahi 15,96\n\ - " CFI_ADJUST_CFA_OFFSET(-96)" \n\ - l 14,48(15)\n\ - lm 2,5,32(15)\n\ - br 1\n\ -1: .long fixup-1b\n\ - " CFI_ENDPROC "\n\ - .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\ -\n\ - .globl _dl_runtime_profile\n\ - .type _dl_runtime_profile, @function\n\ - .align 16\n\ - " CFI_STARTPROC "\n\ -_dl_runtime_profile:\n\ - # save registers\n\ - stm 2,5,32(15)\n\ - st 14,48(15)\n\ - lr 0,15\n\ - ahi 15,-96\n\ - " CFI_ADJUST_CFA_OFFSET(96)"\n\ - st 0,0(15)\n\ - # load args saved by PLT\n\ - lm 2,3,120(15)\n\ - # load return address as third parameter\n\ - lr 4,14\n\ - basr 1,0\n\ -0: ahi 1,1f-0b\n\ - l 14,0(1)\n\ - bas 14,0(14,1) # call fixup\n\ - lr 1,2 # function addr returned in r2\n\ - # restore registers\n\ - ahi 15,96\n\ - " CFI_ADJUST_CFA_OFFSET(-96)" \n\ - l 14,48(15)\n\ - lm 2,5,32(15)\n\ - br 1\n\ -1: .long profile_fixup-1b\n\ - " CFI_ENDPROC "\n\ - .size _dl_runtime_profile, .-_dl_runtime_profile\n\ -"); -#else -#define ELF_MACHINE_RUNTIME_TRAMPOLINE \ - asm ( "\ - .text\n\ - .globl _dl_runtime_resolve\n\ - .globl _dl_runtime_profile\n\ - .type _dl_runtime_resolve, @function\n\ - .type _dl_runtime_profile, @function\n\ - .align 16\n\ - " CFI_STARTPROC "\n\ -_dl_runtime_resolve:\n\ -_dl_runtime_profile:\n\ - # save registers\n\ - stm 2,5,32(15)\n\ - st 14,48(15)\n\ - lr 0,15\n\ - ahi 15,-96\n\ - " CFI_ADJUST_CFA_OFFSET(96)"\n\ - st 0,0(15)\n\ - # load args saved by PLT\n\ - lm 2,3,120(15)\n\ - # load return address as third parameter\n\ - lr 4,14\n\ - basr 1,0\n\ -0: ahi 1,1f-0b\n\ - l 14,0(1)\n\ - bas 14,0(14,1) # call fixup\n\ - lr 1,2 # function addr returned in r2\n\ - # restore registers\n\ - ahi 15,96\n\ - " CFI_ADJUST_CFA_OFFSET(-96)" \n\ - l 14,48(15)\n\ - lm 2,5,32(15)\n\ - br 1\n\ -1: .long fixup-1b\n\ - " CFI_ENDPROC "\n\ - .size _dl_runtime_resolve, .-_dl_runtime_resolve\n\ - .size _dl_runtime_profile, .-_dl_runtime_profile\n\ -"); -#endif - /* Mask identifying addresses reserved for the user program, where the dynamic linker should not map anything. */ #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL @@ -375,15 +258,20 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc, return value; } +/* Names of the architecture-specific auditing callback functions. */ +#define ARCH_LA_PLTENTER s390_32_gnu_pltenter +#define ARCH_LA_PLTEXIT s390_32_gnu_pltexit + #endif /* !dl_machine_h */ -#ifdef RESOLVE +#ifdef RESOLVE_MAP /* Perform the relocation specified by RELOC and SYM (which is fully resolved). MAP is the object containing the reloc. */ -static inline void +auto inline void +__attribute__ ((always_inline)) elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, const Elf32_Sym *sym, const struct r_found_version *version, void *const reloc_addr_arg) @@ -417,17 +305,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, #ifndef RESOLVE_CONFLICT_FIND_MAP const Elf32_Sym *const refsym = sym; #endif -#if defined USE_TLS && !defined RTLD_BOOTSTRAP struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value; -#else - Elf32_Addr value = RESOLVE (&sym, version, r_type); - -# ifndef RTLD_BOOTSTRAP - if (sym) -# endif - value += sym->st_value; -#endif /* use TLS and !RTLD_BOOTSTRAP */ switch (r_type) { @@ -539,7 +418,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, } } -static inline void +auto inline void +__attribute__ ((always_inline)) elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc, void *const reloc_addr_arg) { @@ -547,7 +427,8 @@ elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc, *reloc_addr = l_addr + reloc->r_addend; } -static inline void +auto inline void +__attribute__ ((always_inline)) elf_machine_lazy_rel (struct link_map *map, Elf32_Addr l_addr, const Elf32_Rela *reloc) { @@ -567,4 +448,4 @@ elf_machine_lazy_rel (struct link_map *map, _dl_reloc_bad_type (map, r_type, 1); } -#endif /* RESOLVE */ +#endif /* RESOLVE_MAP */ diff --git a/sysdeps/s390/s390-32/dl-trampoline.S b/sysdeps/s390/s390-32/dl-trampoline.S new file mode 100644 index 0000000000..fbbbc189db --- /dev/null +++ b/sysdeps/s390/s390-32/dl-trampoline.S @@ -0,0 +1,134 @@ +/* PLT trampolines. s390 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. */ + +/* This code is used in dl-runtime.c to call the `fixup' function + and then redirect to the address it returns. */ + +/* The PLT stubs will call _dl_runtime_resolve/_dl_runtime_profile + * with the following linkage: + * r2 - r6 : parameter registers + * f0, f2 : floating point parameter registers + * 24(r15), 28(r15) : PLT arguments PLT1, PLT2 + * 96(r15) : additional stack parameters + * The normal clobber rules for function calls apply: + * r0 - r5 : call clobbered + * r6 - r13 : call saved + * r14 : return address (call clobbered) + * r15 : stack pointer (call saved) + * f4, f6 : call saved + * f0 - f3, f5, f7 - f15 : call clobbered + */ + +#include <sysdep.h> + + .text + .globl _dl_runtime_resolve + .type _dl_runtime_resolve, @function + cfi_startproc + .align 16 +_dl_runtime_resolve: + stm %r2,%r5,32(%r15) # save registers + st %r14,8(%r15) + lr %r0,%r15 # create stack frame + ahi %r15,-96 + cfi_adjust_cfa_offset (96) + st 0,0(%r15) + lm %r2,%r3,120(%r15) # load args saved by PLT + basr %r1,0 +0: l %r14,1f-0b(%r1) + bas %r14,0(%r14,%r1) # call resolver + lr %r1,%r2 # function addr returned in r2 + ahi %r15,96 # remove stack frame + cfi_adjust_cfa_offset (-96) + l %r14,8(15) # restore registers + lm %r2,%r5,32(%r15) + br %r1 +1: .long _dl_fixup - 0b + cfi_endproc + .size _dl_runtime_resolve, .-_dl_runtime_resolve + + +#ifndef PROF + .globl _dl_runtime_profile + .type _dl_runtime_profile, @function + cfi_startproc + .align 16 +_dl_runtime_profile: + stm %r2,%r6,32(%r15) # save registers + std %f0,56(%r15) + std %f2,64(%r15) + st %r6,8(%r15) + st %r12,12(%r15) + st %r14,16(%r15) + lr %r12,%r15 # create stack frame + cfi_def_cfa_register (12) + ahi %r15,-96 + st %r12,0(%r15) + lm %r2,%r3,24(%r12) # load arguments saved by PLT + lr %r4,%r14 # return address as third parameter + basr %r1,0 +0: l %r14,6f-0b(%r1) + la %r5,32(%r12) # pointer to struct La_s390_32_regs + la %r6,20(%r12) # long int * framesize + bas %r14,0(%r14,%r1) # call resolver + lr %r1,%r2 # function addr returned in r2 + icm %r0,15,20(%r12) # load & test framesize + jnm 2f + lm %r2,%r6,32(%r12) + ld %f0,56(%r12) + ld %f2,64(%r12) + basr %r14,%r1 # call resolved function +1: lr %r15,%r12 # remove stack frame + cfi_def_cfa_register (15) + l %r14,16(%r15) # restore registers + l %r12,12(%r15) + l %r6,8(%r15) + br %r14 + cfi_def_cfa_register (12) +2: jz 4f # framesize == 0 ? + ahi %r0,7 # align framesize to 8 + lhi %r2,-8 + nr %r0,%r2 + slr %r15,%r0 # make room for framesize bytes + st %r12,0(%r15) + la %r2,96(%r15) + la %r3,96(%r12) + srl %r0,3 +3: mvc 0(8,%r2),0(%r3) # copy additional parameters + la %r2,8(%r2) + la %r3,8(%r3) + brct %r0,3b +4: lm %r2,%r6,32(%r12) # load register parameters + ld %f0,56(%r12) + ld %f2,64(%r12) + basr %r14,%r1 # call resolved function + stm %r2,%r3,72(%r12) + std %f0,80(%r12) + lm %r2,%r3,24(%r12) # load arguments saved by PLT + basr %r1,0 +5: l %r14,7f-5b(%r1) + la %r4,32(%r12) # pointer to struct La_s390_32_regs + la %r5,72(%r12) # pointer to struct La_s390_32_retval + basr %r14,%r1 # call _dl_call_pltexit + j 1b +6: .long _dl_profile_fixup - 0b +7: .long _dl_call_pltexit - 5b + cfi_endproc + .size _dl_runtime_profile, .-_dl_runtime_profile +#endif diff --git a/sysdeps/s390/s390-32/elf/setjmp.S b/sysdeps/s390/s390-32/elf/setjmp.S index 0d1fa8e41d..ed28008a56 100644 --- a/sysdeps/s390/s390-32/elf/setjmp.S +++ b/sysdeps/s390/s390-32/elf/setjmp.S @@ -1,5 +1,5 @@ /* setjmp for s390, ELF version. - Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Copyright (C) 2000, 2002, 2005 Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). This file is part of the GNU C Library. @@ -46,10 +46,23 @@ END (__setjmp) ENTRY(__sigsetjmp) .Linternal_sigsetjmp: +#ifdef PTR_MANGLE + stm %r6,%r13,0(%r2) /* store registers in jmp_buf */ + lr %r4,%r14 + lr %r5,%r15 + PTR_MANGLE (%r4, %r1) + PTR_MANGLE2 (%r5, %r1) + stm %r4,%r5,32(%r2) +#else stm %r6,%r15,0(%r2) /* store registers in jmp_buf */ +#endif std %f4,40(%r2) std %f6,48(%r2) -#ifdef PIC +#if defined NOT_IN_libc && defined IS_IN_rtld + /* In ld.so we never save the signal mask. */ + lhi %r2,0 + br %r14 +#elif defined PIC /* We cannot use the PLT, because it requires that %r12 be set, but we can't save and restore our caller's value. Instead, we do an indirect jump through the GOT. */ diff --git a/sysdeps/s390/s390-32/elf/start.S b/sysdeps/s390/s390-32/elf/start.S index a09acb5d89..f7290106ce 100644 --- a/sysdeps/s390/s390-32/elf/start.S +++ b/sysdeps/s390/s390-32/elf/start.S @@ -1,5 +1,6 @@ /* Startup code compliant to the ELF s390 ABI. - Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). This file is part of the GNU C Library. @@ -88,9 +89,9 @@ _start: l %r12,.L5-.Llit(%r13) # load .got pointer la %r6,0(%r13,%r6) la %r5,0(%r13,%r5) - la %r2,0(%r13,%r2) - la %r1,0(%r13,%r1) la %r12,0(%r13,%r12) + l %r2,0(%r12,%r2) + la %r1,0(%r13,%r1) #endif /* ok, now branch to the libc main routine */ @@ -108,7 +109,7 @@ _start: #else .L1: .long __libc_csu_init-.Llit .L2: .long __libc_csu_fini-.Llit -.L3: .long main-.Llit +.L3: .long main@GOT .L4: .long __libc_start_main@plt-.Llit .L5: .long _GLOBAL_OFFSET_TABLE_-.Llit #endif diff --git a/sysdeps/s390/s390-32/s390-mcount.S b/sysdeps/s390/s390-32/s390-mcount.S index 8ecdd0edae..6d11f9bbdb 100644 --- a/sysdeps/s390/s390-32/s390-mcount.S +++ b/sysdeps/s390/s390-32/s390-mcount.S @@ -81,4 +81,4 @@ C_LABEL(_mcount) ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(_mcount)) #undef mcount -weak_alias(_mcount, mcount) +weak_alias (_mcount, mcount) diff --git a/sysdeps/s390/s390-32/setjmp.S b/sysdeps/s390/s390-32/setjmp.S index dc4862b2a6..b943085e93 100644 --- a/sysdeps/s390/s390-32/setjmp.S +++ b/sysdeps/s390/s390-32/setjmp.S @@ -1,5 +1,5 @@ /* - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2005 Free Software Foundation, Inc. Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). This file is part of the GNU C Library. @@ -29,10 +29,23 @@ /* R2 = pointer to jmp_buf, R3 = savemask */ ENTRY(__sigsetjmp) +#ifdef PTR_MANGLE + stm %r6,%r13,0(%r2) /* store registers in jmp_buf */ + lr %r4,%r14 + lr %r5,%r15 + PTR_MANGLE (%r4, %r1) + PTR_MANGLE2 (%r5, %r1) + stm %r4,%r5,32(%r2) +#else stm %r6,%r15,0(%r2) /* store registers in jmp_buf */ +#endif std %f4,40(%r2) std %f6,48(%r2) -#ifdef PIC +#if defined NOT_IN_libc && defined IS_IN_rtld + /* In ld.so we never save the signal mask. */ + lhi %r2,0 + br %r14 +#elif defined PIC /* We cannot use the PLT, because it requires that %r12 be set, but we can't save and restore our caller's value. Instead, we do an indirect jump through the GOT. */ |