S/390: Add support for STT_GNU_IFUNC symbols.

Add support for STT_GNU_IFUNC symbols and the new R_390_IRELATIVE
relocation.  Provide optimized version of memcpy, memset, and memcmp
for z10 and z196.
This commit is contained in:
Andreas Krebbel 2012-07-12 13:04:55 +02:00
parent a98430587c
commit 08f43f9bbf
22 changed files with 1218 additions and 103 deletions

View File

@ -1,3 +1,29 @@
2012-07-19 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
* elf/elf.h (R_390_IRELATIVE): New definition.
* sysdeps/s390/s390-64/dl-machine.h (elf_machine_rela): Invoke the
resolver function for IFUNC symbols. Support R_390_IRELATIVE.
(elf_machine_lazy_rel): Support R_390_IRELATIVE.
* sysdeps/s390/s390-32/dl-machine.h (elf_machine_rela):
(elf_machine_lazy_rel): Likewise.
* sysdeps/s390/dl-irel.h: New file.
* sysdeps/s390/s390-64/memcpy.S: New asm code.
* sysdeps/s390/s390-64/memset.S: New asm code.
* sysdeps/s390/s390-64/memcmp.S: New asm code.
* sysdeps/s390/s390-64/multiarch/memset.S: New file.
* sysdeps/s390/s390-64/multiarch/ifunc-resolve.c: New file.
* sysdeps/s390/s390-64/multiarch/memcmp.S: New file.
* sysdeps/s390/s390-64/multiarch/memcpy.S: New file.
* sysdeps/s390/s390-64/multiarch/Makefile: New file.
* sysdeps/s390/s390-32/multiarch/ifunc-resolve.c: New file.
* sysdeps/s390/s390-32/multiarch/Makefile: New file.
* sysdeps/s390/s390-32/multiarch/memcmp.S: New file.
* sysdeps/s390/s390-32/multiarch/memcpy.S: New file.
* sysdeps/s390/s390-32/multiarch/memset.S: New file.
* sysdeps/s390/s390-32/memcpy.S: New asm code.
* sysdeps/s390/s390-32/memset.S: New asm code.
* sysdeps/s390/s390-32/memcmp.S: New asm code.
2012-07-17 Marek Polacek <polacek@redhat.com>
[BZ #14349]

5
NEWS
View File

@ -12,6 +12,11 @@ Version 2.17
6778, 14042, 14151, 14154, 14157, 14173, 14283, 14328, 14331, 14337,
14347, 14349
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
Optimized versions of memcpy, memset, and memcmp added for System z10 and
zEnterprise z196.
Implemented by Andreas Krebbel.
Version 2.16

View File

@ -2627,8 +2627,9 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
block offset. */
#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */
/* Keep this the last entry. */
#define R_390_NUM 61
#define R_390_NUM 62
/* CRIS relocations. */

52
sysdeps/s390/dl-irel.h Normal file
View File

@ -0,0 +1,52 @@
/* Machine-dependent ELF indirect relocation inline functions.
Version for S/390 32 and 64 bit.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#ifndef _DL_IREL_H
#define _DL_IREL_H
#include <stdio.h>
#include <unistd.h>
#include <ldsodefs.h>
#define ELF_MACHINE_IRELA 1
static inline ElfW(Addr)
__attribute ((always_inline))
elf_ifunc_invoke (ElfW(Addr) addr)
{
return ((ElfW(Addr) (*) (unsigned long int)) (addr)) (GLRO(dl_hwcap));
}
static inline void
__attribute ((always_inline))
elf_irela (const ElfW(Rela) *reloc)
{
ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset;
const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
{
ElfW(Addr) value = elf_ifunc_invoke(reloc->r_addend);
*reloc_addr = value;
}
else
__libc_fatal ("unexpected reloc type in static binary");
}
#endif /* dl-irel.h */

View File

@ -1,6 +1,5 @@
/* Machine-dependent ELF dynamic relocation inline functions. S390 Version.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2011
Free Software Foundation, Inc.
Copyright (C) 2000-2012 Free Software Foundation, Inc.
Contributed by Carl Pederson & Martin Schwidefsky.
This file is part of the GNU C Library.
@ -27,6 +26,7 @@
#include <string.h>
#include <link.h>
#include <sysdeps/s390/dl-procinfo.h>
#include <dl-irel.h>
/* This is an older, now obsolete value. */
#define EM_S390_OLD 0xA390
@ -305,8 +305,21 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Elf32_Addr value = sym == NULL ? 0 : 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 = elf_ifunc_invoke (value);
switch (r_type)
{
case R_390_IRELATIVE:
value = map->l_addr + reloc->r_addend;
if (__builtin_expect (!skip_ifunc, 1))
value = elf_ifunc_invoke (value);
*reloc_addr = value;
break;
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
*reloc_addr = value + reloc->r_addend;
@ -444,6 +457,13 @@ elf_machine_lazy_rel (struct link_map *map,
map->l_mach.plt
+ (((Elf32_Addr) reloc_addr) - map->l_mach.gotplt) * 8;
}
else if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
{
Elf32_Addr value = map->l_addr + reloc->r_addend;
if (__builtin_expect (!skip_ifunc, 1))
value = elf_ifunc_invoke (value);
*reloc_addr = value;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}

View File

@ -0,0 +1,66 @@
/* memcmp - compare two memory blocks. 32 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of first memory area
%r3 = address of second memory area
%r4 = number of bytes to compare. */
.text
#ifdef USE_MULTIARCH
ENTRY(memcmp_g5)
#else
ENTRY(memcmp)
#endif
.machine "g5"
basr %r5,0
.L_G5_16:
ltr %r4,%r4
je .L_G5_4
ahi %r4,-1
lr %r1,%r4
srl %r1,8
ltr %r1,%r1
jne .L_G5_12
ex %r4,.L_G5_17-.L_G5_16(%r5)
.L_G5_4:
ipm %r2
sll %r2,2
sra %r2,30
br %r14
.L_G5_12:
clc 0(256,%r3),0(%r2)
jne .L_G5_4
la %r3,256(%r3)
la %r2,256(%r2)
brct %r1,.L_G5_12
ex %r4,.L_G5_17-.L_G5_16(%r5)
j .L_G5_4
.L_G5_17:
clc 0(1,%r3),0(%r2)
#ifdef USE_MULTIARCH
END(memcmp_g5)
#else
END(memcmp)
libc_hidden_builtin_def (memcmp)
weak_alias(memcmp, bcmp)
#endif

View File

@ -1,7 +1,6 @@
/* memcpy - copy a block from source to destination. S/390 version.
Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -17,42 +16,67 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of destination memory area
%r3 = address of source memory area
%r4 = number of bytes to copy. */
#include "sysdep.h"
#include "asm-syntax.h"
.text
#ifdef USE_MULTIARCH
ENTRY(memcpy_g5)
#else
ENTRY(memcpy)
ltr %r4,%r4
jz .L3
ahi %r4,-1 # length - 1
lr %r1,%r2 # copy destination address
lr %r5,%r4
srl %r5,8
ltr %r5,%r5 # < 256 bytes to move ?
jz .L1
chi %r5,255 # > 1MB to move ?
jh .L4
.L0: mvc 0(256,%r1),0(%r3) # move in 256 byte chunks
la %r1,256(%r1)
la %r3,256(%r3)
brct %r5,.L0
.L1: bras %r5,.L2 # setup base pointer for execute
mvc 0(1,%r1),0(%r3) # instruction for execute
.L2: ex %r4,0(%r5) # execute mvc with length ((%r4)&255)+1
.L3: br %r14
# data copies > 1MB are faster with mvcle.
.L4: ahi %r4,1 # length + 1
lr %r5,%r4 # source length
lr %r4,%r3 # source address
lr %r3,%r5 # destination length = source length
.L5: mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L5
lr %r2,%r1 # return destination address
br %r14
#endif
.machine "g5"
st %r13,52(%r15)
.cfi_offset 13, -44
basr %r13,0
.L_G5_16:
ltr %r4,%r4
je .L_G5_4
ahi %r4,-1
lr %r5,%r4
srl %r5,8
ltr %r5,%r5
lr %r1,%r2
jne .L_G5_12
ex %r4,.L_G5_17-.L_G5_16(%r13)
.L_G5_4:
l %r13,52(%r15)
br %r14
.L_G5_13:
chi %r5,4096 # Switch to mvcle for copies >1MB
jh memcpy_mvcle
.L_G5_12:
mvc 0(256,%r1),0(%r3)
la %r1,256(%r1)
la %r3,256(%r3)
brct %r5,.L_G5_12
ex %r4,.L_G5_17-.L_G5_16(%r13)
j .L_G5_4
.L_G5_17:
mvc 0(1,%r1),0(%r3)
#ifdef USE_MULTIARCH
END(memcpy_g5)
#else
END(memcpy)
libc_hidden_builtin_def (memcpy)
#endif
ENTRY(memcpy_mvcle)
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
ahi %r4,1 # length + 1
lr %r5,%r4 # source length
lr %r4,%r3 # source address
lr %r3,%r5 # destination length = source length
.L_MVCLE_1:
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lr %r2,%r1 # return destination address
br %r14
END(memcpy_mvcle)

View File

@ -1,7 +1,6 @@
/* Set a block of memory to some byte value. For IBM S390
Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -17,28 +16,50 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/*
* R2 = address to memory area
* R3 = byte to fill memory with
* R4 = number of bytes to fill
*/
#include "sysdep.h"
#include "asm-syntax.h"
.text
/* INPUT PARAMETERS
%r2 = address to memory area
%r3 = byte to fill memory with
%r4 = number of bytes to fill. */
.text
#ifdef USE_MULTIARCH
ENTRY(memset_g5)
#else
ENTRY(memset)
ltr %r4,%r4
jz .L1
lr %r0,%r2 # save source address
lr %r1,%r3 # move pad byte to R1
lr %r3,%r4
sr %r4,%r4 # no source for MVCLE, only a pad byte
sr %r5,%r5
.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend
jo .L0
lr %r2,%r0 # return value is source address
.L1:
br %r14
#endif
.machine "g5"
basr %r5,0
.L_G5_19:
ltr %r4,%r4
je .L_G5_4
stc %r3,0(%r2)
chi %r4,1
lr %r1,%r2
je .L_G5_4
ahi %r4,-2
lr %r3,%r4
srl %r3,8
ltr %r3,%r3
jne .L_G5_14
ex %r4,.L_G5_20-.L_G5_19(%r5)
.L_G5_4:
br %r14
.L_G5_14:
mvc 1(256,%r1),0(%r1)
la %r1,256(%r1)
brct %r3,.L_G5_14
ex %r4,.L_G5_20-.L_G5_19(%r5)
j .L_G5_4
.L_G5_20:
mvc 1(1,%r1),0(%r1)
#ifdef USE_MULTIARCH
END(memset_g5)
#else
END(memset)
libc_hidden_builtin_def (memset)
#endif

View File

@ -0,0 +1,9 @@
ASFLAGS-.o += -Wa,-mzarch
ASFLAGS-.os += -Wa,-mzarch
ASFLAGS-.op += -Wa,-mzarch
ASFLAGS-.og += -Wa,-mzarch
ASFLAGS-.ob += -Wa,-mzarch
ASFLAGS-.oS += -Wa,-mzarch
ifeq ($(subdir),string)
sysdep_routines += ifunc-resolve memset memcpy memcmp
endif

View File

@ -0,0 +1,69 @@
/* IFUNC resolver function for CPU specific functions.
32 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <dl-procinfo.h>
#define STFLE_BITS_Z10 34 /* General instructions extension */
#define STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
#ifndef NOT_IN_libc
#define IFUNC_RESOLVE(FUNC) \
asm (".globl " #FUNC "\n\t" \
".type " #FUNC ",@gnu_indirect_function\n\t" \
".set " #FUNC ",resolve_" #FUNC "\n\t" \
".globl __GI_" #FUNC "\n\t" \
".set __GI_" #FUNC "," #FUNC "\n"); \
\
extern void *FUNC##_z10; \
extern void *FUNC##_z196; \
extern void *FUNC##_g5; \
\
void *resolve_##FUNC (unsigned long int dl_hwcap) \
{ \
if ((dl_hwcap & HWCAP_S390_STFLE) \
&& (dl_hwcap & HWCAP_S390_HIGH_GPRS)) /* Implies zarch */ \
{ \
/* We want just 1 double word to be returned. */ \
register unsigned long reg0 asm("0") = 0; \
unsigned long long stfle_bits; \
\
asm volatile(".insn s,0xb2b00000,%0" "\n\t" /* stfle */ \
: "=QS" (stfle_bits), "+d" (reg0) \
: : "cc"); \
\
if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z196))) != 0) \
return &FUNC##_z196; \
else if ((stfle_bits & (1ULL << (63 - STFLE_BITS_Z10))) != 0) \
return &FUNC##_z10; \
} \
return &FUNC##_g5; \
}
IFUNC_RESOLVE(memset)
IFUNC_RESOLVE(memcmp)
asm(".weak bcmp ; bcmp = memcmp");
/* In the static lib memcpy is needed before the reloc is resolved. */
#ifdef SHARED
IFUNC_RESOLVE(memcpy)
#endif
#endif

View File

@ -0,0 +1,102 @@
/* CPU specific memcmp implementations. 32 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of first memory area
%r3 = address of second memory area
%r4 = number of bytes to compare. */
.text
#ifndef NOT_IN_libc
ENTRY(memcmp_z196)
.machine "z196"
ltr %r4,%r4
je .L_Z196_4
ahi %r4,-1
srlk %r1,%r4,8
ltr %r1,%r1
jne .L_Z196_2
.L_Z196_3:
exrl %r4,.L_Z196_14
.L_Z196_4:
ipm %r2
sll %r2,2
sra %r2,30
br %r14
.L_Z196_17:
la %r3,256(%r3)
la %r2,256(%r2)
ahi %r1,-1
je .L_Z196_3
.L_Z196_2:
pfd 1,512(%r3)
pfd 1,512(%r2)
clc 0(256,%r3),0(%r2)
je .L_Z196_17
ipm %r2
sll %r2,2
sra %r2,30
br %r14
.L_Z196_14:
clc 0(1,%r3),0(%r2)
END(memcmp_z196)
ENTRY(memcmp_z10)
.machine "z10"
ltr %r4,%r4
je .L_Z10_4
ahi %r4,-1
lr %r1,%r4
srl %r1,8
cijlh %r1,0,.L_Z10_12
.L_Z10_3:
exrl %r4,.L_Z10_15
.L_Z10_4:
ipm %r2
sll %r2,2
sra %r2,30
br %r14
.L_Z10_12:
pfd 1,512(%r3)
pfd 1,512(%r2)
clc 0(256,%r3),0(%r2)
jne .L_Z10_4
la %r3,256(%r3)
la %r2,256(%r2)
brct %r1,.L_Z10_12
j .L_Z10_3
.L_Z10_15:
clc 0(1,%r3),0(%r2)
END(memcmp_z10)
#endif
#include "../memcmp.S"
#ifdef NOT_IN_libc
.globl memcmp
.set memcmp,memcmp_g5
.weak bcmp
.set bcmp,memcmp_g5
#endif

View File

@ -0,0 +1,96 @@
/* CPU specific memcpy implementations. 32 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = target operands address
%r3 = source operands address
%r4 = number of bytes to copy. */
.text
#if defined SHARED && !defined NOT_IN_libc
ENTRY(memcpy_z196)
.machine "z196"
llgfr %r4,%r4
ltgr %r4,%r4
je .L_Z196_4
aghi %r4,-1
lr %r1,%r2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_5
.L_Z196_3:
exrl %r4,.L_Z196_14
.L_Z196_4:
br %r14
.L_Z196_5:
cgfi %r5,262144 # Switch to mvcle for copies >64MB
jh memcpy_mvcle
.L_Z196_2:
pfd 1,768(%r3)
pfd 2,768(%r1)
mvc 0(256,%r1),0(%r3)
aghi %r5,-1
la %r1,256(%r1)
la %r3,256(%r3)
jne .L_Z196_2
j .L_Z196_3
.L_Z196_14:
mvc 0(1,%r1),0(%r3)
END(memcpy_z196)
ENTRY(memcpy_z10)
.machine "z10"
llgfr %r4,%r4
cgije %r4,0,.L_Z10_4
aghi %r4,-1
lr %r1,%r2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_13
.L_Z10_3:
exrl %r4,.L_Z10_15
.L_Z10_4:
br %r14
.L_Z10_13:
cgfi %r5,65535 # Switch to mvcle for copies >16MB
jh memcpy_mvcle
.L_Z10_12:
pfd 1,768(%r3)
pfd 2,768(%r1)
mvc 0(256,%r1),0(%r3)
la %r1,256(%r1)
la %r3,256(%r3)
brctg %r5,.L_Z10_12
j .L_Z10_3
.L_Z10_15:
mvc 0(1,%r1),0(%r3)
END(memcpy_z10)
#endif
#include "../memcpy.S"
#if !defined SHARED || defined NOT_IN_libc
.globl memcpy
.set memcpy,memcpy_g5
#endif

View File

@ -0,0 +1,111 @@
/* Set a block of memory to some byte value. 32 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of memory area
%r3 = byte to fill memory with
%r4 = number of bytes to fill. */
.text
#ifndef NOT_IN_libc
ENTRY(memset_z196)
.machine "z196"
llgfr %r4,%r4
ltgr %r4,%r4
je .L_Z196_4
stc %r3,0(%r2)
lr %r1,%r2
cghi %r4,1
je .L_Z196_4
aghi %r4,-2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_1
.L_Z196_3:
exrl %r4,.L_Z196_17
.L_Z196_4:
br %r14
.L_Z196_1:
cgfi %r5,1048576
jh memset_mvcle # Switch to mvcle for >256MB
.L_Z196_2:
pfd 2,1024(%r1)
mvc 1(256,%r1),0(%r1)
aghi %r5,-1
la %r1,256(%r1)
jne .L_Z196_2
j .L_Z196_3
.L_Z196_17:
mvc 1(1,%r1),0(%r1)
END(memset_z196)
ENTRY(memset_z10)
.machine "z10"
llgfr %r4,%r4
cgije %r4,0,.L_Z10_4
stc %r3,0(%r2)
lr %r1,%r2
cgije %r4,1,.L_Z10_4
aghi %r4,-2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_15
.L_Z10_3:
exrl %r4,.L_Z10_18
.L_Z10_4:
br %r14
.L_Z10_15:
cgfi %r5,163840 # Switch to mvcle for >40MB
jh memset_mvcle
.L_Z10_14:
pfd 2,1024(%r1)
mvc 1(256,%r1),0(%r1)
la %r1,256(%r1)
brctg %r5,.L_Z10_14
j .L_Z10_3
.L_Z10_18:
mvc 1(1,%r1),0(%r1)
END(memset_z10)
ENTRY(memset_mvcle)
ahi %r4,2 # take back the change done by the caller
lr %r0,%r2 # save source address
lr %r1,%r3 # move pad byte to R1
lr %r3,%r4
sr %r4,%r4 # no source for MVCLE, only a pad byte
sr %r5,%r5
.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend
jo .L0
lr %r2,%r0 # return value is source address
.L1:
br %r14
END(memset_mvcle)
#endif
#include "../memset.S"
#ifdef NOT_IN_libc
.globl memset
.set memset,memset_g5
#endif

View File

@ -1,6 +1,6 @@
/* Machine-dependent ELF dynamic relocation inline functions.
64 bit S/390 Version.
Copyright (C) 2001-2005, 2006, 2011 Free Software Foundation, Inc.
Copyright (C) 2001-2012 Free Software Foundation, Inc.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
This file is part of the GNU C Library.
@ -26,6 +26,9 @@
#include <sys/param.h>
#include <string.h>
#include <link.h>
#include <dl-irel.h>
#define ELF_MACHINE_IRELATIVE R_390_IRELATIVE
/* This is an older, now obsolete value. */
#define EM_S390_OLD 0xA390
@ -280,8 +283,21 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
Elf64_Addr value = sym == NULL ? 0 : 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 = elf_ifunc_invoke (value);
switch (r_type)
{
case R_390_IRELATIVE:
value = map->l_addr + reloc->r_addend;
if (__builtin_expect (!skip_ifunc, 1))
value = elf_ifunc_invoke (value);
*reloc_addr = value;
break;
case R_390_GLOB_DAT:
case R_390_JMP_SLOT:
*reloc_addr = value + reloc->r_addend;
@ -426,6 +442,13 @@ elf_machine_lazy_rel (struct link_map *map,
map->l_mach.plt
+ (((Elf64_Addr) reloc_addr) - map->l_mach.gotplt) * 4;
}
else if (__builtin_expect (r_type == R_390_IRELATIVE, 1))
{
Elf64_Addr value = map->l_addr + reloc->r_addend;
if (__builtin_expect (!skip_ifunc, 1))
value = elf_ifunc_invoke (value);
*reloc_addr = value;
}
else
_dl_reloc_bad_type (map, r_type, 1);
}

View File

@ -0,0 +1,64 @@
/* memcmp - compare two memory blocks. 64 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of first memory area
%r3 = address of second memory area
%r4 = number of bytes to compare. */
.text
#ifdef USE_MULTIARCH
ENTRY(memcmp_z900)
#else
ENTRY(memcmp)
#endif
.machine "z900"
ltgr %r4,%r4
je .L_Z900_4
aghi %r4,-1
srlg %r1,%r4,8
ltgr %r1,%r1
jne .L_Z900_12
.L_Z900_3:
larl %r1,.L_Z900_15
ex %r4,0(%r1)
.L_Z900_4:
ipm %r2
sllg %r2,%r2,34
srag %r2,%r2,62
br %r14
.L_Z900_12:
clc 0(256,%r3),0(%r2)
jne .L_Z900_4
la %r3,256(%r3)
la %r2,256(%r2)
brctg %r1,.L_Z900_12
j .L_Z900_3
.L_Z900_15:
clc 0(1,%r3),0(%r2)
#ifdef USE_MULTIARCH
END(memcmp_z900)
#else
END(memcmp)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
#endif

View File

@ -1,7 +1,6 @@
/* memcpy - copy a block from source to destination. 64 bit S/390 version.
Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
Copyright (C) 2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -17,41 +16,66 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of destination memory area
%r3 = address of source memory area
%r4 = number of bytes to copy. */
#include "sysdep.h"
#include "asm-syntax.h"
.text
.text
#ifdef USE_MULTIARCH
ENTRY(memcpy_z900)
#else
ENTRY(memcpy)
ltgr %r4,%r4
jz .L3
aghi %r4,-1 # length - 1
lgr %r1,%r2 # copy destination address
srlg %r5,%r4,8
ltgr %r5,%r5 # < 256 bytes to mvoe ?
jz .L1
chi %r5,255 # > 1 MB to move ?
jh .L4
.L0: mvc 0(256,%r1),0(%r3) # move in 256 byte chunks
la %r1,256(%r1)
la %r3,256(%r3)
brctg %r5,.L0
.L1: bras %r5,.L2 # setup base pointer for execute
mvc 0(1,%r1),0(%r3) # instruction for execute
.L2: ex %r4,0(%r5) # execute mvc with length ((%r4)&255)+1
.L3: br %r14
# data copies > 1MB are faster with mvcle.
.L4: aghi %r4,1 # length + 1
lgr %r5,%r4 # source length
lgr %r4,%r3 # source address
lgr %r3,%r5 # destination length = source length
.L5: mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L5
lgr %r2,%r1 # return destination address
br %r14
#endif
.machine "z900"
ltgr %r4,%r4
je .L_Z900_4
aghi %r4,-1
srlg %r5,%r4,8
ltgr %r5,%r5
lgr %r1,%r2
jne .L_Z900_13
.L_Z900_3:
larl %r5,.L_Z900_15
ex %r4,0(%r5)
.L_Z900_4:
br %r14
.L_Z900_13:
chi %r5,4096 # Switch to mvcle for copies >1MB
jh memcpy_mvcle
.L_Z900_12:
mvc 0(256,%r1),0(%r3)
la %r1,256(%r1)
la %r3,256(%r3)
brctg %r5,.L_Z900_12
j .L_Z900_3
.L_Z900_15:
mvc 0(1,%r1),0(%r3)
#ifdef USE_MULTIARCH
END(memcpy_z900)
#else
END(memcpy)
libc_hidden_builtin_def (memcpy)
#endif
ENTRY(memcpy_mvcle)
# Using as standalone function will result in unexpected
# results since the length field is incremented by 1 in order to
# compensate the changes already done in the functions above.
aghi %r4,1 # length + 1
lgr %r5,%r4 # source length
lgr %r4,%r3 # source address
lgr %r3,%r5 # destination length = source length
.L_MVCLE_1:
mvcle %r2,%r4,0 # thats it, MVCLE is your friend
jo .L_MVCLE_1
lgr %r2,%r1 # return destination address
br %r14
END(memcpy_mvcle)

View File

@ -17,27 +17,48 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of memory area
%r3 = byte to fill memory with
%r4 = number of bytes to fill. */
#include "sysdep.h"
#include "asm-syntax.h"
.text
.text
#ifdef USE_MULTIARCH
ENTRY(memset_z900)
#else
ENTRY(memset)
ltgr %r4,%r4
jz .L1
lgr %r0,%r2 # save source address
lgr %r1,%r3 # move pad byte to R1
lgr %r3,%r4
sgr %r4,%r4 # no source for MVCLE, only a pad byte
sgr %r5,%r5
.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend
jo .L0
lgr %r2,%r0 # return value is source address
.L1:
br %r14
#endif
.machine "z900"
ltgr %r4,%r4
je .L_Z900_4
stc %r3,0(%r2)
cghi %r4,1
lgr %r1,%r2
je .L_Z900_4
aghi %r4,-2
srlg %r3,%r4,8
ltgr %r3,%r3
jne .L_Z900_14
.L_Z900_3:
larl %r3,.L_Z900_18
ex %r4,0(%r3)
.L_Z900_4:
br %r14
.L_Z900_14:
mvc 1(256,%r1),0(%r1)
la %r1,256(%r1)
brctg %r3,.L_Z900_14
j .L_Z900_3
.L_Z900_18:
mvc 1(1,%r1),0(%r1)
#ifdef USE_MULTIARCH
END(memset_z900)
#else
END(memset)
libc_hidden_builtin_def (memset)
#endif

View File

@ -0,0 +1,3 @@
ifeq ($(subdir),string)
sysdep_routines += ifunc-resolve memset memcpy memcmp
endif

View File

@ -0,0 +1,74 @@
/* IFUNC resolver function for CPU specific functions.
64 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <dl-procinfo.h>
#define STFLE_BITS_Z10 34 /* General instructions extension */
#define STFLE_BITS_Z196 45 /* Distinct operands, pop ... */
#ifndef NOT_IN_libc
#define IFUNC_RESOLVE(FUNC) \
asm (".globl " #FUNC "\n\t" \
".type " #FUNC ",@gnu_indirect_function\n\t" \
".set " #FUNC ",resolve_" #FUNC "\n\t" \
".globl __GI_" #FUNC "\n\t" \
".set __GI_" #FUNC "," #FUNC "\n"); \
\
extern void *FUNC##_z10; \
extern void *FUNC##_z196; \
extern void *FUNC##_z900; \
\
void *resolve_##FUNC (unsigned long int dl_hwcap) \
{ \
if (dl_hwcap & HWCAP_S390_STFLE) \
{ \
/* We want just 1 double word to be returned. */ \
register unsigned long reg0 asm("0") = 0; \
unsigned long stfle_bits; \
\
asm volatile(".machine push" "\n\t" \
".machine \"z9-109\"" "\n\t" \
"stfle %0" "\n\t" \
".machine pop" "\n" \
: "=QS" (stfle_bits), "+d" (reg0) \
: : "cc"); \
\
if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z196))) != 0) \
return &FUNC##_z196; \
else if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z10))) != 0) \
return &FUNC##_z10; \
else \
return &FUNC##_z900; \
} \
else \
return &FUNC##_z900; \
}
IFUNC_RESOLVE(memset)
IFUNC_RESOLVE(memcmp)
asm(".weak bcmp ; bcmp = memcmp");
/* In the static lib memcpy is needed before the reloc is resolved. */
#ifdef SHARED
IFUNC_RESOLVE(memcpy)
#endif
#endif

View File

@ -0,0 +1,101 @@
/* CPU specific memcmp implementations. 64 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of first memory area
%r3 = address of second memory area
%r4 = number of bytes to compare. */
.text
#ifndef NOT_IN_libc
ENTRY(memcmp_z196)
.machine "z196"
ltgr %r4,%r4
je .L_Z196_4
aghi %r4,-1
srlg %r1,%r4,8
ltgr %r1,%r1
jne .L_Z196_2
.L_Z196_3:
exrl %r4,.L_Z196_14
.L_Z196_4:
ipm %r2
sllg %r2,%r2,34
srag %r2,%r2,62
br %r14
.L_Z196_17:
la %r3,256(%r3)
la %r2,256(%r2)
aghi %r1,-1
je .L_Z196_3
.L_Z196_2:
pfd 1,512(%r3)
pfd 1,512(%r2)
clc 0(256,%r3),0(%r2)
je .L_Z196_17
ipm %r2
sllg %r2,%r2,34
srag %r2,%r2,62
br %r14
.L_Z196_14:
clc 0(1,%r3),0(%r2)
END(memcmp_z196)
ENTRY(memcmp_z10)
.machine "z10"
ltgr %r4,%r4
je .L_Z10_4
aghi %r4,-1
srlg %r1,%r4,8
cgijlh %r1,0,.L_Z10_12
.L_Z10_3:
exrl %r4,.L_Z10_15
.L_Z10_4:
ipm %r2
sllg %r2,%r2,34
srag %r2,%r2,62
br %r14
.L_Z10_12:
pfd 1,512(%r3)
pfd 1,512(%r2)
clc 0(256,%r3),0(%r2)
jne .L_Z10_4
la %r3,256(%r3)
la %r2,256(%r2)
brctg %r1,.L_Z10_12
j .L_Z10_3
.L_Z10_15:
clc 0(1,%r3),0(%r2)
END(memcmp_z10)
#endif
#include "../memcmp.S"
#ifdef NOT_IN_libc
.globl memcmp
.set memcmp,memcmp_z900
.weak bcmp
.set bcmp,memcmp_z900
#endif

View File

@ -0,0 +1,94 @@
/* CPU specific memcpy implementations. 64 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = target operands address
%r3 = source operands address
%r4 = number of bytes to copy. */
.text
#if defined SHARED && !defined NOT_IN_libc
ENTRY(memcpy_z196)
.machine "z196"
ltgr %r4,%r4
je .L_Z196_4
aghi %r4,-1
lgr %r1,%r2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_5
.L_Z196_3:
exrl %r4,.L_Z196_14
.L_Z196_4:
br %r14
.L_Z196_5:
cgfi %r5,262144 # Switch to mvcle for copies >64MB
jh memcpy_mvcle
.L_Z196_2:
pfd 1,768(%r3)
pfd 2,768(%r1)
mvc 0(256,%r1),0(%r3)
aghi %r5,-1
la %r1,256(%r1)
la %r3,256(%r3)
jne .L_Z196_2
j .L_Z196_3
.L_Z196_14:
mvc 0(1,%r1),0(%r3)
END(memcpy_z196)
ENTRY(memcpy_z10)
.machine "z10"
cgije %r4,0,.L_Z10_4
aghi %r4,-1
lgr %r1,%r2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_13
.L_Z10_3:
exrl %r4,.L_Z10_15
.L_Z10_4:
br %r14
.L_Z10_13:
cgfi %r5,65535 # Switch to mvcle for copies >16MB
jh memcpy_mvcle
.L_Z10_12:
pfd 1,768(%r3)
pfd 2,768(%r1)
mvc 0(256,%r1),0(%r3)
la %r1,256(%r1)
la %r3,256(%r3)
brctg %r5,.L_Z10_12
j .L_Z10_3
.L_Z10_15:
mvc 0(1,%r1),0(%r3)
END(memcpy_z10)
#endif
#include "../memcpy.S"
#if !defined SHARED || defined NOT_IN_libc
.globl memcpy
.set memcpy,memcpy_z900
#endif

View File

@ -0,0 +1,109 @@
/* Set a block of memory to some byte value. 64 bit S/390 version.
Copyright (C) 2012 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, see
<http://www.gnu.org/licenses/>. */
#include "sysdep.h"
#include "asm-syntax.h"
/* INPUT PARAMETERS
%r2 = address of memory area
%r3 = byte to fill memory with
%r4 = number of bytes to fill. */
.text
#ifndef NOT_IN_libc
ENTRY(memset_z196)
.machine "z196"
ltgr %r4,%r4
je .L_Z196_4
stc %r3,0(%r2)
lgr %r1,%r2
cghi %r4,1
je .L_Z196_4
aghi %r4,-2
srlg %r5,%r4,8
ltgr %r5,%r5
jne .L_Z196_1
.L_Z196_3:
exrl %r4,.L_Z196_17
.L_Z196_4:
br %r14
.L_Z196_1:
cgfi %r5,1048576
jh memset_mvcle # Switch to mvcle for >256MB
.L_Z196_2:
pfd 2,1024(%r1)
mvc 1(256,%r1),0(%r1)
aghi %r5,-1
la %r1,256(%r1)
jne .L_Z196_2
j .L_Z196_3
.L_Z196_17:
mvc 1(1,%r1),0(%r1)
END(memset_z196)
ENTRY(memset_z10)
.machine "z10"
cgije %r4,0,.L_Z10_4
stc %r3,0(%r2)
lgr %r1,%r2
cgije %r4,1,.L_Z10_4
aghi %r4,-2
srlg %r5,%r4,8
cgijlh %r5,0,.L_Z10_15
.L_Z10_3:
exrl %r4,.L_Z10_18
.L_Z10_4:
br %r14
.L_Z10_15:
cgfi %r5,163840 # Switch to mvcle for >40MB
jh memset_mvcle
.L_Z10_14:
pfd 2,1024(%r1)
mvc 1(256,%r1),0(%r1)
la %r1,256(%r1)
brctg %r5,.L_Z10_14
j .L_Z10_3
.L_Z10_18:
mvc 1(1,%r1),0(%r1)
END(memset_z10)
ENTRY(memset_mvcle)
aghi %r4,2 # take back the change done by the caller
lgr %r0,%r2 # save source address
lgr %r1,%r3 # move pad byte to R1
lgr %r3,%r4 # move length to r3
sgr %r4,%r4 # no source for MVCLE, only a pad byte
sgr %r5,%r5
.L0: mvcle %r2,%r4,0(%r1) # thats it, MVCLE is your friend
jo .L0
lgr %r2,%r0 # return value is source address
.L1:
br %r14
END(memset_mvcle)
#endif
#include "../memset.S"
#ifdef NOT_IN_libc
.globl memset
.set memset,memset_z900
#endif