diff options
author | Ulrich Drepper <drepper@redhat.com> | 1997-03-19 05:47:56 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1997-03-19 05:47:56 +0000 |
commit | e61abf83986463e263de965d487fac5cb083839a (patch) | |
tree | fa0a23e631c0c3e7f7b38c609e7fa808b1275933 /sysdeps | |
parent | 6465cfc9cf96f06a34227b557332f002f109f0ec (diff) | |
download | glibc-e61abf83986463e263de965d487fac5cb083839a.tar.gz glibc-e61abf83986463e263de965d487fac5cb083839a.tar.xz glibc-e61abf83986463e263de965d487fac5cb083839a.zip |
Update. cvs/libc-ud-970318
1997-03-19 01:40 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/sysv/sco3.2.4/Dist: New file. * sysdeps/unix/sysv/sysv4/Dist: Add __getpgid.c and __setpgid.c. * sysdeps/unix/bsd/Dist: Add bsdstat.h, setrgid.c, and setruid.c. * sysdeps/unix/sysv/Dist: Add direct.h. * sysdeps/unix/sysv/linux/Dist: Add netinet/tcp.h. * Make-dist ($(tardir).tar): Prefer writing temporary file to $TMPDIR is available. The default is /tmp. * sysdeps/generic/ip.h: Move to... * sysdeps/generic/netinet/ip.h: ...here. * Makefile (tests): Quote $(CC) argument to isomac program. Patch by H.J. Lu <hjl@gnu.ai.mit.edu>. * sysdeps/i386/setjmp.S (__setjmp): Fix fatal bug where 0 argument is placed in wrong place on the stack. Reported by Marc Lehmann <mlehmann@hildesheim.sgh-net.de>. * sysdeps/tst-setjmp.c: Add new test for above problem. * sysdeps/libm-i387/e_pow.S: Compute PIC addres early. * sysdeps/libm-i387/e_powf.S: Likewise. * sysdeps/libm-i387/e_powl.S: Likewise. 1997-03-18 23:18 Ulrich Drepper <drepper@cygnus.com> * time/offtime.c (__offtime): Change type of `yg' to long int. Reported by a sun <asun@zoology.washington.edu>. 1997-03-18 23:08 a sun <asun@zoology.washington.edu> * sysdeps/unix/sysv/linux/net/if_ppp.h (PPP_VERSION): Define to 2.2.0 to prevent version mismatch. 1997-03-17 19:26 Andreas Jaeger <aj@arthur.pfalz.de> * stdio-common/printf_fphex.c (MIN): Only define MIN if not already defined. 1997-03-14 23:34 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/unix/sysv/linux/powerpc/termbits.h: Leave ioctl numbers in ioctls.h. * elf/rtld.c (_dl_start): Call elf_machine_runtime_setup when the loader first relocates itself. * sysdeps/powerpc/elf/start.c (__start1): Fix bug for static objects. * sysdeps/powerpc/dl-machine.h (elf_machine_rela): Fix bugs in jump slot relocation. Prefer relative branches (some PowerPC chips don't predict absolute branches). (elf_machine_runtime_setup): Simplify and correct expressions. (RTLD_START): Fix bug changing _dl_starting_up. * sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c: Added. Deal with strange Linux/PPC padding of initial stack. 1997-03-11 04:14 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/unix/sysv/linux/powerpc/termbits.h: Increase NCCS to 39, for future expansion. * sysdeps/unix/sysv/linux/powerpc/sys/kernel_termios.h: Added. * sysdeps/powerpc/dl-machine.h (elf_machine_rela): Explain why it can't have a switch statement. * sysdeps/powerpc/elf/start.c (__start1): Explain why it can't be static. * sysdeps/powerpc/elf/start.c (_start): Use .previous to avoid confusing gcc's idea of the current section. * sysdeps/powerpc/dl-machine.h (ELF_MACHINE_RUNTIME_TRAMPOLINE, RTLD_START): Likewise. 1997-03-08 09:10 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/dl-machine.h (elf_machine_rela, elf_machine_runtime_setup): Flush data & instruction caches when necessary, for 603/604 support. Add better support for large PLTs. (elf_machine_rela): Remove relocations that wouldn't work if anyone ever used them. Use memcpy for copy reloc, it'll be safe. Never target branch relocations at a PLT entry. * sysdeps/powerpc/bsd-setjmp.S: Make jump to PLT entry if we are generating PIC. * sysdeps/powerpc/bsd-_setjmp.S: Likewise. * sysdeps/powerpc/setjmp.S: Likewise. * sysdeps/unix/sysv/linux/powerpc/clone.S: Likewise. * sysdeps/unix/sysv/linux/powerpc/socket.S: Likewise. * sysdeps/unix/sysv/linux/powerpc/syscall.S: Likewise. * sysdeps/unix/sysv/linux/powerpc/sysdep.h: Likewise. * sysdeps/powerpc/elf/start.c: Clean up. * sysdeps/powerpc/__longjmp.S: Return 'value' as result from setjmp call. * sysdeps/unix/sysv/linux/powerpc/statbuf.h: New file. 1997-03-09 12:36 H.J. Lu <hjl@gnu.ai.mit.edu> * Make-dist (srcs): Add $(test-srcs). * MakeTAGS (all-sources): Likewise. * Makerules (depfiles, common-mostlyclean): Likewise. * Rules (tests): Likewise. 1997-03-18 05:28 Roland McGrath <roland@frob.com> * elf/dl-reloc.c (RESOLVE): Don't try to resolve ocal symbols. 1997-03-17 21:39 Philip Blundell <phil@london.uk.eu.org> * nis/nss_nis/nis-service.c (_nss_nis_getservbyname_r): Allow protocol=NULL to match any protocol rather than returning an error. 1997-03-17 19:00 Philip Blundell <phil@london.uk.eu.org> * nss/nss_files/files-service.c (servbyname): Match any protocol if proto==NULL. 1997-03-18 05:17 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/sysv/linux/alpha/fcntlbits.h: Don't define O_NORW. * sysdeps/unix/sysv/linux/fcntlbits.h: Likewise. Proposed by Thomas Bushnell, n/BSG. 1997-03-18 07:53 H.J. Lu <hjl@gnu.ai.mit.edu> * sysdeps/generic/setenv.c (setenv): Don't copy name when we reuse the buffer for replacement. 1997-03-16 19:30 H.J. Lu <hjl@gnu.ai.mit.edu> * sysdeps/unix/sysv/linux/syscalls.list: Add sys_fstat, sys_lstat and sys_stat. 1997-03-17 12:43 Thorsten Kukuk <kukuk@vt.uni-paderborn.de> Add NIS+ functions * shlib-versions: Add libnss_nisplus. * nis/Makefile: Add NIS+ source files. * nis/nis_call.c: New file. * nis/nis_clone.c: New file. * nis/nis_error.c: New file. * nis/nis_file.c: New file. * nis/nis_free.c: New file. * nis/nis_intern.c: New file. * nis/nis_intern.h: New file. * nis/nis_local_names.c: New file. * nis/nis_names.c: New file. * nis/nis_print.c: New file. * nis/nis_server.c: New file. * nis/nis_subr.c: New file. * nis/nis_table.c: New file. * nis/nis_xdr.c: New file. * nis/nss-nisplus.h: New file. * nis/nss_nisplus/nisplus-alias.c: New file. * nis/nss_nisplus/nisplus-ethers.c: New file. * nis/nss_nisplus/nisplus-grp.c: New file. * nis/nss_nisplus/nisplus-hosts.c: New file. * nis/nss_nisplus/nisplus-netgrp.c: New file. * nis/nss_nisplus/nisplus-network.c: New file. * nis/nss_nisplus/nisplus-proto.c: New file. * nis/nss_nisplus/nisplus-publickey.c: New file. * nis/nss_nisplus/nisplus-pwd.c: New file. * nis/nss_nisplus/nisplus-rpc.c: New file. * nis/nss_nisplus/nisplus-service.c: New file. * nis/nss_nisplus/nisplus-spwd.c: New file. * nis/rpcsvc/nis.h: New file. * nis/rpcsvc/nis.x: New file. * nis/rpcsvc/nis_object.x: New file. * nis/rpcsvc/nis_tags.h: New file. * nis/rpcsvc/nislib.h: New file. 1997-03-17 12:52 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> * mach/devstream.c (output/write_some): Don't try and write more than IO_INBAND_MAX in a single call to device_write_inband. * sysdeps/libm-ieee754/w_atan2.c: Don't ignore exception if library * sysdeps/libm-ieee754/w_atan2f.c: Likewise. * sysdeps/libm-ieee754/w_atan2l.c: Likewise. * sysdeps/unix/sysv/linux/sys/mman.h (msync): Add description for * stdlib/atoll.c: Undefine atoll, not atol.
Diffstat (limited to 'sysdeps')
30 files changed, 862 insertions, 333 deletions
diff --git a/sysdeps/generic/setenv.c b/sysdeps/generic/setenv.c index 6d0c23114c..94dc7472ec 100644 --- a/sysdeps/generic/setenv.c +++ b/sysdeps/generic/setenv.c @@ -132,9 +132,9 @@ setenv (name, value, replace) return -1; } *ep = new; + memcpy (*ep, name, namelen); + (*ep)[namelen] = '='; } - memcpy (*ep, name, namelen); - (*ep)[namelen] = '='; memcpy (&(*ep)[namelen + 1], value, vallen); } diff --git a/sysdeps/i386/setjmp.S b/sysdeps/i386/setjmp.S index 23e2b74401..203c2d16d0 100644 --- a/sysdeps/i386/setjmp.S +++ b/sysdeps/i386/setjmp.S @@ -1,21 +1,21 @@ /* setjmp for i386. -Copyright (C) 1995, 1996 Free Software Foundation, Inc. -This file is part of the GNU C Library. + Copyright (C) 1995, 1996, 1997 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 Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 -Library General Public License for more details. + 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 + Library General Public License for more details. -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ #include <sysdep.h> #define _ASM @@ -24,7 +24,9 @@ Cambridge, MA 02139, USA. */ /* Binary compatibility entry point. */ ENTRY (__setjmp) popl %eax /* Pop return address. */ + popl %ecx /* Pop jmp_buf. */ pushl $0 /* Push zero argument. */ + pushl %ecx /* Push jmp_buf. */ pushl %eax /* Push back return address. */ ENTRY (__sigsetjmp) diff --git a/sysdeps/libm-i387/e_pow.S b/sysdeps/libm-i387/e_pow.S index efe184168b..ab6b454339 100644 --- a/sysdeps/libm-i387/e_pow.S +++ b/sysdeps/libm-i387/e_pow.S @@ -64,6 +64,13 @@ nan: .byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f ENTRY(__ieee754_pow) fldl 12(%esp) // y fxam + +#ifdef PIC + call 1f +1: popl %ecx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx +#endif + fnstsw movb %ah, %dl andb $0x45, %ah @@ -76,12 +83,6 @@ ENTRY(__ieee754_pow) cmpb $0x01, %ah // is y == NaN ? je 30f -#ifdef PIC - call 1f -1: popl %ecx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx -#endif - fldl 4(%esp) // x : y subl $8,%esp diff --git a/sysdeps/libm-i387/e_powf.S b/sysdeps/libm-i387/e_powf.S index 54af93c961..48316464ef 100644 --- a/sysdeps/libm-i387/e_powf.S +++ b/sysdeps/libm-i387/e_powf.S @@ -64,6 +64,13 @@ nan: .byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f ENTRY(__ieee754_powf) flds 8(%esp) // y fxam + +#ifdef PIC + call 1f +1: popl %ecx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx +#endif + fnstsw movb %ah, %dl andb $0x45, %ah @@ -76,12 +83,6 @@ ENTRY(__ieee754_powf) cmpb $0x01, %ah // is y == NaN ? je 30f -#ifdef PIC - call 1f -1: popl %ecx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx -#endif - flds 4(%esp) // x : y subl $4, %esp diff --git a/sysdeps/libm-i387/e_powl.S b/sysdeps/libm-i387/e_powl.S index 3cfb96b213..dba725aa77 100644 --- a/sysdeps/libm-i387/e_powl.S +++ b/sysdeps/libm-i387/e_powl.S @@ -64,6 +64,13 @@ nan: .byte 0, 0, 0, 0, 0, 0, 0xff, 0x7f ENTRY(__ieee754_powl) fldt 16(%esp) // y fxam + +#ifdef PIC + call 1f +1: popl %ecx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx +#endif + fnstsw movb %ah, %dl andb $0x45, %ah @@ -76,12 +83,6 @@ ENTRY(__ieee754_powl) cmpb $0x01, %ah // is y == NaN ? je 30f -#ifdef PIC - call 1f -1: popl %ecx - addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx -#endif - fldt 4(%esp) // x : y subl $8,%esp diff --git a/sysdeps/powerpc/__longjmp.S b/sysdeps/powerpc/__longjmp.S index 928b5c540a..da621e22c0 100644 --- a/sysdeps/powerpc/__longjmp.S +++ b/sysdeps/powerpc/__longjmp.S @@ -62,5 +62,6 @@ ENTRY (__longjmp) lfd 30,((JB_FPRS+16*2)*4)(3) lwz 31,((JB_GPRS+17)*4)(3) lfd 31,((JB_FPRS+17*2)*4)(3) + mr 3,4 blr END (__longjmp) diff --git a/sysdeps/powerpc/bsd-_setjmp.S b/sysdeps/powerpc/bsd-_setjmp.S index 90171ea616..a9aefcc977 100644 --- a/sysdeps/powerpc/bsd-_setjmp.S +++ b/sysdeps/powerpc/bsd-_setjmp.S @@ -25,5 +25,9 @@ ENTRY (_setjmp) li 4,0 /* Set second argument to 0. */ - b C_SYMBOL_NAME(__sigsetjmp) +#ifdef PIC + b __sigsetjmp@plt +#else + b __sigsetjmp +#endif END (_setjmp) diff --git a/sysdeps/powerpc/bsd-setjmp.S b/sysdeps/powerpc/bsd-setjmp.S new file mode 100644 index 0000000000..19c2fe308c --- /dev/null +++ b/sysdeps/powerpc/bsd-setjmp.S @@ -0,0 +1,33 @@ +/* BSD `setjmp' entry point to `sigsetjmp (..., 1)'. PowerPC version. + Copyright (C) 1994, 1997 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This just does a tail-call to `__sigsetjmp (ARG, 1)'. + We cannot do it in C because it must be a tail-call, so frame-unwinding + in setjmp doesn't clobber the state restored by longjmp. */ + +#include <sysdep.h> + +ENTRY (setjmp) + li 4,1 /* Set second argument to 1. */ +#ifdef PIC + b __sigsetjmp@plt +#else + b __sigsetjmp +#endif +END (setjmp) diff --git a/sysdeps/powerpc/dl-machine.h b/sysdeps/powerpc/dl-machine.h index a60a29723d..541892cdfc 100644 --- a/sysdeps/powerpc/dl-machine.h +++ b/sysdeps/powerpc/dl-machine.h @@ -26,6 +26,14 @@ /* stuff for the PLT */ #define PLT_INITIAL_ENTRY_WORDS 18 #define PLT_LONGBRANCH_ENTRY_WORDS 10 +#define PLT_DOUBLE_SIZE (1<<13) +#define PLT_ENTRY_START_WORDS(entry_number) \ + (PLT_INITIAL_ENTRY_WORDS + (entry_number)*2 + \ + ((entry_number) > PLT_DOUBLE_SIZE ? \ + ((entry_number) - PLT_DOUBLE_SIZE)*2 : \ + 0)) +#define PLT_DATA_START_WORDS(num_entries) PLT_ENTRY_START_WORDS(num_entries) + #define OPCODE_ADDI(rd,ra,simm) \ (0x38000000 | (rd) << 21 | (ra) << 16 | (simm) & 0xffff) #define OPCODE_ADDIS(rd,ra,simm) \ @@ -44,6 +52,19 @@ #define OPCODE_LI(rd,simm) OPCODE_ADDI(rd,0,simm) #define OPCODE_SLWI(ra,rs,sh) OPCODE_RLWINM(ra,rs,sh,0,31-sh) +#define PPC_DCBST(where) asm __volatile__ ("dcbst 0,%0" : : "r"(where)) ++#define PPC_SYNC asm __volatile__ ("sync") ++#define PPC_ISYNC asm __volatile__ ("sync; isync") ++#define PPC_ICBI(where) asm __volatile__ ("icbi 0,%0" : : "r"(where)) + +/* Use this when you've modified some code, but it won't be in the + instruction fetch queue (or when it doesn't matter if it is). */ +#define MODIFIED_CODE_NOQUEUE(where) \ + do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); } while (0) +/* Use this when it might be in the instruction queue. */ +#define MODIFIED_CODE(where) \ + do { PPC_DCBST(where); PPC_SYNC; PPC_ICBI(where); PPC_ISYNC; } while (0) + /* Return nonzero iff E_MACHINE is compatible with the running host. */ static inline int @@ -53,7 +74,8 @@ elf_machine_matches_host (Elf32_Half e_machine) } -/* Return the link-time address of _DYNAMIC, the first value in the GOT. */ +/* Return the link-time address of _DYNAMIC, stored as + the first value in the GOT. */ static inline Elf32_Addr elf_machine_dynamic (void) { @@ -79,11 +101,11 @@ elf_machine_load_address (void) get confused. asm ("bcl 20,31,0f ;" - "0: mflr 0 ;" - "lis %0,0b@ha;" - "addi %0,%0,0b@l;" - "subf %0,%0,0" - : "=b" (addr) : : "r0", "lr"); + "0: mflr 0 ;" + "lis %0,0b@ha;" + "addi %0,%0,0b@l;" + "subf %0,%0,0" + : "=b" (addr) : : "r0", "lr"); doesn't work, because the linker doesn't have to (and in fact doesn't) update the @ha and @l references; the loader (which runs after this @@ -134,7 +156,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, if (rinfo == R_PPC_NONE) return; - if (sym && ELF32_ST_TYPE (sym->st_info) == STT_SECTION || + assert (sym != NULL); + if (ELF32_ST_TYPE (sym->st_info) == STT_SECTION || rinfo == R_PPC_RELATIVE) { /* Has already been relocated. */ @@ -143,133 +166,124 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, } else { - assert (sym != NULL); - if (rinfo == R_PPC_JMP_SLOT) - loadbase = (Elf32_Word) (char *) RESOLVE (&sym, - version, DL_LOOKUP_NOPLT); + int flags; + + /* We never want to use a PLT entry as the destination of a + reloc, when what is being relocated is a branch. This is + partly for efficiency, but mostly so we avoid loops. */ + if (rinfo == R_PPC_REL24 || + rinfo == R_PPC_ADDR24 || + rinfo == R_PPC_JMP_SLOT) + flags = DL_LOOKUP_NOPLT; + else if (rinfo == R_PPC_COPY) + flags = DL_LOOKUP_NOEXEC; else - loadbase = (Elf32_Word) (char *) RESOLVE (&sym, version, 0); + flags = 0; + + loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version, flags)); if (sym == NULL) { /* Weak symbol that wasn't actually defined anywhere. */ - assert (loadbase == 0); + assert(loadbase == 0); finaladdr = reloc->r_addend; } else - finaladdr = (loadbase + (Elf32_Word)(char *)sym->st_value - + reloc->r_addend); + finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value + + reloc->r_addend); } - switch (rinfo) + /* This is an if/else if chain because GCC 2.7.2.[012] turns case + statements into non-PIC table lookups. When a later version + comes out that fixes this, this should be changed. */ + if (rinfo == R_PPC_ADDR16_LO) { - case R_PPC_UADDR16: - case R_PPC_ADDR16_LO: - case R_PPC_ADDR16: *(Elf32_Half*) reloc_addr = finaladdr; - break; - - case R_PPC_ADDR16_HI: + } + else if (rinfo == R_PPC_ADDR16_HI) + { *(Elf32_Half*) reloc_addr = finaladdr >> 16; - break; - - case R_PPC_ADDR16_HA: + } + else if (rinfo == R_PPC_ADDR16_HA) + { *(Elf32_Half*) reloc_addr = finaladdr + 0x8000 >> 16; - break; - - case R_PPC_REL24: - { - Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr; - assert (delta << 6 >> 6 == delta); - *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc; - } - break; - - case R_PPC_UADDR32: - case R_PPC_GLOB_DAT: - case R_PPC_ADDR32: - case R_PPC_RELATIVE: + } + else if (rinfo == R_PPC_REL24) + { + Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr; + assert (delta << 6 >> 6 == delta); + *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc; + } + else if (rinfo == R_PPC_UADDR32 || + rinfo == R_PPC_GLOB_DAT || + rinfo == R_PPC_ADDR32 || + rinfo == R_PPC_RELATIVE) + { *reloc_addr = finaladdr; - break; - - case R_PPC_ADDR24: + } + else if (rinfo == R_PPC_ADDR24) + { + assert (finaladdr << 6 >> 6 == finaladdr); *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc; - break; - - case R_PPC_REL14_BRTAKEN: - case R_PPC_REL14_BRNTAKEN: - case R_PPC_REL14: - { - Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr; - *reloc_addr = *reloc_addr & 0xffdf0003 | delta & 0xfffc; - if (rinfo == R_PPC_REL14_BRTAKEN && delta >= 0 || - rinfo == R_PPC_REL14_BRNTAKEN && delta < 0) - *reloc_addr |= 0x00200000; - } - break; - - case R_PPC_COPY: - { - /* Can't use memcpy (because we can't call any functions here). */ - int i; - for (i = 0; i < sym->st_size; ++i) - ((unsigned char *) reloc_addr)[i] = - ((unsigned char *)finaladdr)[i]; - } - break; - - case R_PPC_REL32: + } + else if (rinfo == R_PPC_COPY) + { + /* Memcpy is safe to use here, because ld.so doesn't have any + COPY relocs (it's self-contained). */ + memcpy (reloc_addr, (char *) finaladdr, sym->st_size); + } + else if (rinfo == R_PPC_REL32) + { *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr; - break; - - case R_PPC_JMP_SLOT: - if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) - *reloc_addr = OPCODE_BA (finaladdr); + } + else if (rinfo == R_PPC_JMP_SLOT) + { + Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr; + if (delta << 6 >> 6 == delta) + *reloc_addr = OPCODE_B(delta); + else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000) + *reloc_addr = OPCODE_BA(finaladdr); else { - Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr; - if (delta <= 0x01fffffc && delta >= 0xfe000000) - *reloc_addr = OPCODE_B (delta); + Elf32_Word *plt = (Elf32_Word *)((char *)map->l_addr + + map->l_info[DT_PLTGOT]->d_un.d_val); + Elf32_Word index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2; + Elf32_Word offset = index * 2 + PLT_INITIAL_ENTRY_WORDS; + + if (index >= PLT_DOUBLE_SIZE) + { + /* Slots greater than or equal to 2^13 have 4 words + available instead of two. */ + plt[offset ] = OPCODE_LI (11,finaladdr); + plt[offset+1] = OPCODE_ADDIS (11,11,finaladdr + 0x8000 >> 16); + plt[offset+2] = OPCODE_MTCTR (11); + plt[offset+3] = OPCODE_BCTR (); + } else { - Elf32_Word *plt = - (Elf32_Word *) ((char *) map->l_addr - + map->l_info[DT_PLTGOT]->d_un.d_val); - Elf32_Word index =((reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS) - / 2); - int num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val - / sizeof (Elf32_Rela)); - int rel_offset_words = (PLT_INITIAL_ENTRY_WORDS - + num_plt_entries * 2); - - if (index >= (1 << 13)) - { - /* Indexes greater than or equal to 2^13 have 4 - words available instead of two. */ - plt[index * 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_LI (11, finaladdr); - plt[index * 2 + 1 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16); - plt[index * 2 + 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_MTCTR (11); - plt[index * 2 + 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_BCTR (); - } - else - { - plt[index * 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_LI (11, index * 4); - plt[index * 2 + 1 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_B(-(4 * (index * 2 + 1 + PLT_INITIAL_ENTRY_WORDS - + PLT_LONGBRANCH_ENTRY_WORDS))); - plt[index + rel_offset_words] = finaladdr; - } + Elf32_Word num_plt_entries; + Elf32_Word rel_offset_words; + + num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val + / sizeof(Elf32_Rela)); + rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries); + + plt[offset ] = OPCODE_LI (11,index * 4); + plt[offset+1] = OPCODE_B (-(4 * (offset + 1 + - PLT_LONGBRANCH_ENTRY_WORDS))); + plt[index + rel_offset_words] = finaladdr; } } - break; - - default: - assert (! "unexpected dynamic reloc type"); + MODIFIED_CODE(reloc_addr); } + else + assert (! "unexpected dynamic reloc type"); + + if (rinfo == R_PPC_ADDR16_LO || + rinfo == R_PPC_ADDR16_HI || + rinfo == R_PPC_ADDR16_HA || + rinfo == R_PPC_REL24 || + rinfo == R_PPC_ADDR24) + MODIFIED_CODE_NOQUEUE (reloc_addr); } #define ELF_MACHINE_NO_REL 1 @@ -282,64 +296,58 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, /* 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. */ - -/* This code does not presently work if there are more than 2^13 PLT - entries. */ static inline void elf_machine_runtime_setup (struct link_map *map, int lazy) { - Elf32_Word *plt; - int i; - Elf32_Word num_plt_entries; - Elf32_Word rel_offset_words; - extern void _dl_runtime_resolve (void); - if (map->l_info[DT_JMPREL]) { + int i; /* Fill in the PLT. Its initial contents are directed to a function earlier in the PLT which arranges for the dynamic linker to be called back. */ - plt = (Elf32_Word *) ((char *) map->l_addr + - map->l_info[DT_PLTGOT]->d_un.d_val); - num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val - / sizeof (Elf32_Rela)); - rel_offset_words = PLT_INITIAL_ENTRY_WORDS + num_plt_entries * 2; + Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr + + map->l_info[DT_PLTGOT]->d_un.d_val); + Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val + / sizeof (Elf32_Rela)); + Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries); + extern void _dl_runtime_resolve (void); + Elf32_Word size_modified; if (lazy) for (i = 0; i < num_plt_entries; i++) - if (i >= (1 << 13)) - { - plt[i * 2 + (i - (1 << 13)) * 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_LI (11, i * 4); - plt[i * 2 + (i - (1 << 13)) * 2 + 1 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_ADDIS (11, 11, i * 4 + 0x8000 >> 16); - plt[i * 2 + (i - (1 << 13)) * 2 + 2 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_B (-(4 * ( i * 2 + 1 + PLT_INITIAL_ENTRY_WORDS))); - } - else - { - plt[i * 2 + PLT_INITIAL_ENTRY_WORDS] = OPCODE_LI (11, i * 4); - plt[i * 2 + 1 + PLT_INITIAL_ENTRY_WORDS] = - OPCODE_B (-(4 * (i * 2 + 1 + PLT_INITIAL_ENTRY_WORDS))); - } - - /* Multiply index of entry, by 0xC. */ - plt[0] = OPCODE_SLWI (12, 11, 1); - plt[1] = OPCODE_ADD (11, 12, 11); - if ((Elf32_Word) (char *) _dl_runtime_resolve <= 0x01fffffc || - (Elf32_Word) (char *) _dl_runtime_resolve >= 0xfe000000) { - plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map); - plt[3] = OPCODE_ADDIS (12, 12, - (Elf32_Word) (char *) map + 0x8000 >> 16); - plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve); + Elf32_Word offset = PLT_ENTRY_START_WORDS(i); + + if (i >= PLT_DOUBLE_SIZE) + { + plt[offset ] = OPCODE_LI (11, i * 4); + plt[offset+1] = OPCODE_ADDIS (11, 11, i * 4 + 0x8000 >> 16); + plt[offset+2] = OPCODE_B (-(4 * (offset + 2))); + } + else + { + plt[offset ] = OPCODE_LI (11, i * 4); + plt[offset+1] = OPCODE_B(-(4 * (offset + 1))); + } + + /* Multiply index of entry, by 0xC. */ + plt[0] = OPCODE_SLWI (12, 11, 1); + plt[1] = OPCODE_ADD (11, 12, 11); + if ((Elf32_Word) (char *) _dl_runtime_resolve <= 0x01fffffc + || (Elf32_Word) (char *) _dl_runtime_resolve >= 0xfe000000) + { + plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map); + plt[3] = OPCODE_ADDIS (12, 12, + (Elf32_Word) (char *) map + 0x8000 >> 16); + plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve); + } } else { plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) _dl_runtime_resolve); - plt[3] = OPCODE_ADDIS (12, 12, 0x8000 + - ((Elf32_Word) (char *) _dl_runtime_resolve - >> 16)); + plt[3] = OPCODE_ADDIS(12, 12, 0x8000 + + ((Elf32_Word) (char *) _dl_runtime_resolve + >> 16)); plt[4] = OPCODE_MTCTR (12); plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map); plt[6] = OPCODE_ADDIS (12, 12, ((Elf32_Word) (char *) map @@ -347,21 +355,28 @@ elf_machine_runtime_setup (struct link_map *map, int lazy) plt[7] = OPCODE_BCTR (); } plt[PLT_LONGBRANCH_ENTRY_WORDS] = - OPCODE_ADDIS (11, 11, ((Elf32_Word) (char*) (plt+rel_offset_words) - + 0x8000 >> 16)); + OPCODE_ADDIS (11, 11, (Elf32_Word) (char*) (plt + rel_offset_words) + + 0x8000 >> 16); plt[PLT_LONGBRANCH_ENTRY_WORDS+1] = - OPCODE_LWZ (11, (Elf32_Word) (char*) (plt + rel_offset_words), 11); + OPCODE_LWZ(11,(Elf32_Word)(char*)(plt+rel_offset_words),11); plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11); plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR (); + + size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS; + /* Now we need to keep the caches in sync. */ + for (i = 0; i < size_modified; i+=8) + PPC_DCBST (plt + i); + PPC_SYNC; + for (i = 0; i < size_modified; i+=8) + PPC_ICBI (plt + i); + PPC_ISYNC; } } static inline void elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc) { - if (ELF32_R_TYPE (reloc->r_info) != R_PPC_JMP_SLOT) - assert (! "unexpected PLT reloc type"); - + assert (ELF32_R_TYPE (reloc->r_info) == R_PPC_JMP_SLOT); /* elf_machine_runtime_setup handles this. */ } @@ -369,17 +384,23 @@ elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc) #define elf_machine_relplt elf_machine_rela /* This code is used in dl-runtime.c to call the `fixup' function - and then redirect to the address it returns. */ + and then redirect to the address it returns. It is called + from code built in the PLT by elf_machine_runtime_setup. */ #define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\ .section \".text\" + .align 2 .globl _dl_runtime_resolve + .type _dl_runtime_resolve,@function _dl_runtime_resolve: + # We need to save the registers used to pass parameters. + # We build a stack frame to put them in. stwu 1,-48(1) mflr 0 stw 3,16(1) stw 4,20(1) stw 0,52(1) stw 5,24(1) + # We also need to save some of the condition register fields. mfcr 0 stw 6,28(1) stw 7,32(1) @@ -387,10 +408,13 @@ _dl_runtime_resolve: stw 9,40(1) stw 10,44(1) stw 0,12(1) + # The code that calls this has put parameters for `fixup' in r12 and r11. mr 3,12 mr 4,11 bl fixup + # 'fixup' returns the address we want to branch to. mtctr 3 + # Put the registers back... lwz 0,52(1) lwz 10,44(1) lwz 9,40(1) @@ -403,37 +427,40 @@ _dl_runtime_resolve: lwz 5,24(1) lwz 4,20(1) lwz 3,16(1) + # ...unwind the stack frame, and jump to the PLT entry we updated. addi 1,1,48 bctr +0: + .size _dl_runtime_resolve,0b-_dl_runtime_resolve + # undo '.section text'. + .previous "); /* 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. */ - -/* FIXME! We don't make provision for calling _dl_fini, - because Linux/PPC is somewhat broken. */ + its return value is the user program's entry point. */ #define RTLD_START \ asm ("\ .text - .align 2 + .align 2 .globl _start - .type _start,@function + .type _start,@function _start: # We start with the following on the stack, from top: # argc (4 bytes) # arguments for program (terminated by NULL) # environment variables (terminated by NULL) # arguments for the program loader + # FIXME: perhaps this should do the same trick as elf/start.c? # Call _dl_start with one parameter pointing at argc - mr 3,1 + mr 3,1 # (we have to frob the stack pointer a bit to allow room for # _dl_start to save the link register) - li 4,0 - addi 1,1,-16 - stw 4,0(1) - bl _dl_start@local + li 4,0 + addi 1,1,-16 + stw 4,0(1) + bl _dl_start@local # Now, we do our main work of calling initialisation procedures. # The ELF ABI doesn't say anything about parameters for these, @@ -442,10 +469,10 @@ _start: # passed by value!). # put our GOT pointer in r31 - bl _GLOBAL_OFFSET_TABLE_-4@local - mflr 31 + bl _GLOBAL_OFFSET_TABLE_-4@local + mflr 31 # the address of _start in r30 - mr 30,3 + mr 30,3 # &_dl_argc in 29, &_dl_argv in 27, and _dl_default_scope in 28 lwz 28,_dl_default_scope@got(31) lwz 29,_dl_argc@got(31) @@ -499,13 +526,19 @@ _start: mtlr 0 # and also clear _dl_starting_up lwz 26,_dl_starting_up@got(31) - stw 0,0(3) + stw 0,0(26) # go do it! bctr +0: + .size _start,0b-_start + # undo '.section text'. + .previous "); -#define ELF_PREFERRED_ADDRESS_DATA static ElfW(Addr) _dl_preferred_address = 0; -#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \ +#define ELF_PREFERRED_ADDRESS_DATA \ +static ElfW(Addr) _dl_preferred_address = 0; + +#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \ ( { \ ElfW(Addr) prefd; \ if (mapstartpref != 0 && _dl_preferred_address == 0) \ @@ -516,13 +549,14 @@ _start: prefd = 0; \ else \ prefd = _dl_preferred_address = \ - (_dl_preferred_address - maplength - 0x10000) & \ - ~(_dl_pagesize - 1); \ + ((_dl_preferred_address - maplength - 0x10000) \ + & ~(_dl_pagesize - 1)); \ prefd; \ } ) -#define ELF_FIXED_ADDRESS(loader, mapstart) \ + +#define ELF_FIXED_ADDRESS(loader, mapstart) \ ( { \ - if (mapstart != 0 && _dl_preferred_address == 0) \ + if (mapstart != 0 && _dl_preferred_address < mapstart) \ _dl_preferred_address = mapstart; \ } ) diff --git a/sysdeps/powerpc/elf/start.c b/sysdeps/powerpc/elf/start.c index 9b1cf1c026..001d6aa97c 100644 --- a/sysdeps/powerpc/elf/start.c +++ b/sysdeps/powerpc/elf/start.c @@ -26,22 +26,27 @@ /* Just a little assembler stub before gcc gets its hands on our stack pointer... */ asm ("\ - .text + .section \".text\" + .align 2 .globl _start _start: # save the stack pointer, in case we're statically linked under Linux - mr 8,1 + mr 8,1 # set up an initial stack frame, and clear the LR - addi 1,1,-16 - clrrwi 1,1,4 - li 0,0 - stw 0,0(1) - mtlr 0 + addi 1,1,-16 + clrrwi 1,1,4 + li 0,0 + stw 0,0(1) + mtlr 0 # set r13 to point at the 'small data area' - lis 13,_SDA_BASE_@ha - addi 13,13,_SDA_BASE_@l + lis 13,_SDA_BASE_@ha + addi 13,13,_SDA_BASE_@l # and continue below. - b __start1 + b __start1 +0: + .size _start,0b-_start + # undo '.section text'. + .previous "); /* Define a symbol for the first piece of initialized data. */ @@ -53,38 +58,46 @@ weak_alias (__data_start, data_start) void (*_mach_init_routine) (void); void (*_thread_init_routine) (void); -void __libc_init_first (int argc, char **argv, char **envp); -int main (int argc, char **argv, char **envp, void *auxvec); +extern void __libc_init_first (int argc, char **argv, char **envp); +extern int main (int argc, char **argv, char **envp, void *auxvec); #ifdef HAVE_INITFINI -void _init (void); -void _fini (void); +extern void _init (void); +extern void _fini (void); #endif - +#if 0 +/* I'd like to say this, but it causes GCC to strip the whole procedure + from the object file (this is sort of reasonable, because you've told + GCC that the procedure is unused). :-( */ static void __start1(int argc, char **argv, char **envp, - void *auxvec, void (*exitfn) (void), char **arguments) + void *auxvec, void (*exitfn) (void), + char **stack_on_entry) __attribute__ ((unused)); -static void + +static +#endif +void __start1(int argc, char **argv, char **envp, void *auxvec, void (*exitfn) (void), - char **arguments) + char **stack_on_entry) { /* the PPC SVR4 ABI says that the top thing on the stack will be a NULL pointer, so if not we assume that we're being called - as a statically-linked program by Linux. */ - int abi_compliant_startup = *arguments == NULL; - - if (!abi_compliant_startup) - { - argc = *(int *) arguments; - argv = arguments+1; - envp = argv+argc+1; - auxvec = envp; - while (auxvec != NULL) - auxvec++; - auxvec++; - exitfn = NULL; - } + as a statically-linked program by Linux... */ + if (*stack_on_entry != NULL) + { + /* ...in which case, we have argc as the top thing on the + stack, followed by argv (NULL-terminated), envp (likewise), + and the auxilary vector. */ + argc = *(int *) stack_on_entry; + argv = stack_on_entry + 1; + envp = argv + argc + 1; + auxvec = envp; + while (*(char **) auxvec != NULL) + ++auxvec; + ++auxvec; + exitfn = NULL; + } if (exitfn != NULL) atexit (exitfn); diff --git a/sysdeps/powerpc/setjmp.S b/sysdeps/powerpc/setjmp.S index a2c0b8c53d..755ef6504c 100644 --- a/sysdeps/powerpc/setjmp.S +++ b/sysdeps/powerpc/setjmp.S @@ -62,5 +62,9 @@ ENTRY (__sigsetjmp) stfd 30,((JB_FPRS+16*2)*4)(3) stw 31,((JB_GPRS+17)*4)(3) stfd 31,((JB_FPRS+17*2)*4)(3) +#ifdef PIC + b __sigjmp_save@plt +#else b __sigjmp_save +#endif END (__sigsetjmp) diff --git a/sysdeps/unix/bsd/Dist b/sysdeps/unix/bsd/Dist index 9e0e553aa7..ab3c4f491e 100644 --- a/sysdeps/unix/bsd/Dist +++ b/sysdeps/unix/bsd/Dist @@ -1 +1,4 @@ -bsdtty.h +setrgid.c +setruid.c +bsdstat.h +bsdtty.h diff --git a/sysdeps/unix/sysv/Dist b/sysdeps/unix/sysv/Dist index 14343b6b6f..6ad8e0f653 100644 --- a/sysdeps/unix/sysv/Dist +++ b/sysdeps/unix/sysv/Dist @@ -1 +1,2 @@ +direct.h sysv_termio.h diff --git a/sysdeps/unix/sysv/linux/Dist b/sysdeps/unix/sysv/linux/Dist index 7b94300c6a..d4b6bac217 100644 --- a/sysdeps/unix/sysv/linux/Dist +++ b/sysdeps/unix/sysv/linux/Dist @@ -21,6 +21,7 @@ netinet/igmp.h netinet/in_systm.h netinet/ip_fw.h netinet/ip_icmp.h +netinet/tcp.h netinet/udp.h netipx/ipx.h nfs/nfs.h diff --git a/sysdeps/unix/sysv/linux/alpha/fcntlbits.h b/sysdeps/unix/sysv/linux/alpha/fcntlbits.h index faf198393f..6e1c843ccb 100644 --- a/sysdeps/unix/sysv/linux/alpha/fcntlbits.h +++ b/sysdeps/unix/sysv/linux/alpha/fcntlbits.h @@ -27,7 +27,6 @@ #ifdef __USE_GNU #define O_READ O_RDONLY /* Open for reading. */ #define O_WRITE O_WRONLY /* Open for writing. */ -#define O_NORW 0 /* Open without R/W access. */ #endif /* open/fcntl - O_SYNC is only implemented on blocks devices and on files located on an ext2 file system */ diff --git a/sysdeps/unix/sysv/linux/fcntlbits.h b/sysdeps/unix/sysv/linux/fcntlbits.h index fdc67ce4eb..f6ba880459 100644 --- a/sysdeps/unix/sysv/linux/fcntlbits.h +++ b/sysdeps/unix/sysv/linux/fcntlbits.h @@ -27,7 +27,6 @@ #ifdef __USE_GNU #define O_READ O_RDONLY /* Open for reading. */ #define O_WRITE O_WRONLY /* Open for writing. */ -#define O_NORW 0 /* Open without R/W access. */ #endif /* open/fcntl - O_SYNC is only implemented on blocks devices and on files located on an ext2 file system */ diff --git a/sysdeps/unix/sysv/linux/net/if_ppp.h b/sysdeps/unix/sysv/linux/net/if_ppp.h index 567dccebe3..0f2a979cd6 100644 --- a/sysdeps/unix/sysv/linux/net/if_ppp.h +++ b/sysdeps/unix/sysv/linux/net/if_ppp.h @@ -51,7 +51,7 @@ __BEGIN_DECLS #define PPP_MTU 1500 /* Default MTU (size of Info field) */ #define PPP_MAXMRU 65000 /* Largest MRU we allow */ -#define PPP_VERSION "2.3.0" +#define PPP_VERSION "2.2.0" #define PPP_MAGIC 0x5002 /* Magic value for the ppp structure */ #define PROTO_IPX 0x002b /* protocol numbers */ #define PROTO_DNA_RT 0x0027 /* DNA Routing */ diff --git a/sysdeps/unix/sysv/linux/powerpc/clone.S b/sysdeps/unix/sysv/linux/powerpc/clone.S index e5fa16d8c5..0afd0717f4 100644 --- a/sysdeps/unix/sysv/linux/powerpc/clone.S +++ b/sysdeps/unix/sysv/linux/powerpc/clone.S @@ -71,4 +71,8 @@ child: badargs: li 3,-EINVAL error: +#ifdef PIC + b __syscall_error@plt +#else b __syscall_error +#endif diff --git a/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c new file mode 100644 index 0000000000..eb732d6fb1 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c @@ -0,0 +1,237 @@ +/* Operating system support for run-time dynamic linker. Linux/PPC version. + Copyright (C) 1995, 1996, 1997 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <elf.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <link.h> +#include <unistd.h> +#include <stdarg.h> +#include <string.h> + + +extern int _dl_argc; +extern char **_dl_argv; +extern char **_environ; +extern size_t _dl_pagesize; +extern void _end; +extern void _start (void); + +int __libc_enable_secure; +int __libc_multiple_libcs; /* Defining this here avoids the inclusion + of init-first. */ + +ElfW(Addr) +_dl_sysdep_start (void **start_argptr, + void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum, + ElfW(Addr) *user_entry)) +{ + const ElfW(Phdr) *phdr = NULL; + ElfW(Word) phnum = 0; + ElfW(Addr) user_entry; + ElfW(auxv_t) *av; + uid_t uid = 0; + uid_t euid = 0; + gid_t gid = 0; + gid_t egid = 0; + unsigned int seen; + + user_entry = (ElfW(Addr)) &_start; + _dl_argc = *(long *) start_argptr; + _dl_argv = (char **) start_argptr + 1; + _environ = &_dl_argv[_dl_argc + 1]; + start_argptr = (void **) _environ; + while (*start_argptr) + ++start_argptr; + ++start_argptr; + + if (*start_argptr == 0 && + ((unsigned)(char *)start_argptr & 0xF) != 0) + { + unsigned test_sap = (int)(char *)start_argptr; + test_sap = test_sap + 0xF & ~0xF; + if (*(long *)(char *)test_sap == AT_PHDR) + start_argptr = (void **)(char *)test_sap; + } + + seen = 0; +#define M(type) (1 << (type)) + + for (av = (void *) start_argptr; + av->a_type != AT_NULL; + seen |= M ((++av)->a_type)) + switch (av->a_type) + { + case AT_PHDR: + phdr = av->a_un.a_ptr; + break; + case AT_PHNUM: + phnum = av->a_un.a_val; + break; + case AT_PAGESZ: + _dl_pagesize = av->a_un.a_val; + break; + case AT_ENTRY: + user_entry = av->a_un.a_val; + break; + case AT_UID: + uid = av->a_un.a_val; + break; + case AT_GID: + gid = av->a_un.a_val; + break; + case AT_EUID: + euid = av->a_un.a_val; + break; + case AT_EGID: + egid = av->a_un.a_val; + break; + } + + /* Linux doesn't provide us with any of these values on the stack + when the dynamic linker is run directly as a program. */ + +#define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid () + SEE (UID, uid); + SEE (GID, gid); + SEE (EUID, euid); + SEE (EGID, egid); + + + __libc_enable_secure = uid != euid || gid != egid; + + __brk (0); /* Initialize the break. */ + + if (__sbrk (0) == &_end) + { + /* The dynamic linker was run as a program, and so the initial break + starts just after our bss, at &_end. The malloc in dl-minimal.c + will consume the rest of this page, so tell the kernel to move the + break up that far. When the user program examines its break, it + will see this new value and not clobber our data. */ + size_t pg = __getpagesize (); + + __sbrk (pg - ((&_end - (void *) 0) & pg)); + __sbrk (pg - ((&_end - (void *) 0) & (pg - 1))); + } + + (*dl_main) (phdr, phnum, &user_entry); + return user_entry; +} + +void +_dl_sysdep_start_cleanup (void) +{ +} + +#ifndef MAP_ANON +/* This is only needed if the system doesn't support MAP_ANON. */ + +int +_dl_sysdep_open_zero_fill (void) +{ + return __open ("/dev/zero", O_RDONLY); +} +#endif + +/* Read the whole contents of FILE into new mmap'd space with given + protections. *SIZEP gets the size of the file. */ + +void * +_dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot) +{ + void *result; + struct stat st; + int fd = __open (file, O_RDONLY); + if (fd < 0) + return NULL; + if (__fstat (fd, &st) < 0) + result = NULL; + else + { + /* Map a copy of the file contents. */ + result = __mmap (0, st.st_size, prot, +#ifdef MAP_COPY + MAP_COPY +#else + MAP_PRIVATE +#endif +#ifdef MAP_FILE + | MAP_FILE +#endif + , fd, 0); + if (result == (void *) -1) + result = NULL; + else + *sizep = st.st_size; + } + __close (fd); + return result; +} + +void +_dl_sysdep_fatal (const char *msg, ...) +{ + va_list ap; + + va_start (ap, msg); + do + { + size_t len = strlen (msg); + __write (STDERR_FILENO, msg, len); + msg = va_arg (ap, const char *); + } while (msg); + va_end (ap); + + _exit (127); +} + + +void +_dl_sysdep_error (const char *msg, ...) +{ + va_list ap; + + va_start (ap, msg); + do + { + size_t len = strlen (msg); + __write (STDERR_FILENO, msg, len); + msg = va_arg (ap, const char *); + } while (msg); + va_end (ap); +} + + +void +_dl_sysdep_message (const char *msg, ...) +{ + va_list ap; + + va_start (ap, msg); + do + { + size_t len = strlen (msg); + __write (STDOUT_FILENO, msg, len); + msg = va_arg (ap, const char *); + } while (msg); + va_end (ap); +} diff --git a/sysdeps/unix/sysv/linux/powerpc/kernel_termios.h b/sysdeps/unix/sysv/linux/powerpc/kernel_termios.h new file mode 100644 index 0000000000..acf62a42ca --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/kernel_termios.h @@ -0,0 +1,25 @@ +#ifndef _SYS_KERNEL_TERMIOS_H +#define _SYS_KERNEL_TERMIOS_H 1 +/* The following corresponds to the values from the Linux 2.0.28 kernel. */ + +/* We need the definition of tcflag_t, cc_t, and speed_t. */ +#include <termbits.h> + +#define __KERNEL_NCCS 19 + +struct __kernel_termios + { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_cc[__KERNEL_NCCS]; /* control characters */ + cc_t c_line; /* line discipline */ + int c_ispeed; /* input speed */ + int c_ospeed; /* output speed */ + }; + +#define _HAVE_C_ISPEED 1 +#define _HAVE_C_OSPEED 1 + +#endif /* sys/kernel_termios.h */ diff --git a/sysdeps/unix/sysv/linux/powerpc/socket.S b/sysdeps/unix/sysv/linux/powerpc/socket.S index 32bb8f64cd..12417faac6 100644 --- a/sysdeps/unix/sysv/linux/powerpc/socket.S +++ b/sysdeps/unix/sysv/linux/powerpc/socket.S @@ -76,7 +76,11 @@ ENTRY(P(__,socket)) DO_CALL(SYS_ify(socketcall)) addi 1,1,48 bnslr +#ifdef PIC + b __syscall_error@plt +#else b __syscall_error +#endif PSEUDO_END (P(__,socket)) diff --git a/sysdeps/unix/sysv/linux/powerpc/statbuf.h b/sysdeps/unix/sysv/linux/powerpc/statbuf.h new file mode 100644 index 0000000000..5be5736931 --- /dev/null +++ b/sysdeps/unix/sysv/linux/powerpc/statbuf.h @@ -0,0 +1,79 @@ +/* Copyright (C) 1992, 1995, 1996, 1997 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _STATBUF_H +#define _STATBUF_H 1 + +/* Versions of the `struct stat' data structure. */ +#define _STAT_VER_LINUX 1 +#define _STAT_VER_SVR4 2 +#define _STAT_VER _STAT_VER_LINUX /* The one defined below. */ + +/* Versions of the `xmknod' interface. */ +#define _MKNOD_VER_LINUX 1 +#define _MKNOD_VER_SVR4 2 +#define _MKNOD_VER _MKNOD_VER_LINUX /* The bits defined below. */ + + +struct stat + { + unsigned int st_dev; /* Device. */ + unsigned int st_ino; /* File serial number. */ + unsigned int st_mode; /* File mode. */ + unsigned short int st_nlink; /* Link count. */ + unsigned int st_uid; /* User ID of the file's owner. */ + unsigned int st_gid; /* Group ID of the file's group.*/ + unsigned int st_rdev; /* Device number, if device. */ + long int st_size; /* Size of file, in bytes. */ + unsigned long int st_blksize; /* Optimal block size for I/O. */ +#define _STATBUF_ST_BLKSIZE /* Tell code we have this member. */ + + unsigned long int st_blocks; /* Number of 512-byte blocks allocated. */ + unsigned long int st_atime; /* Time of last access. */ + unsigned long int __unused1; + unsigned long int st_mtime; /* Time of last modification. */ + unsigned long int __unused2; + unsigned long int st_ctime; /* Time of last status change. */ + unsigned long int __unused3; + unsigned long int __unused4; + unsigned long int __unused5; + }; + +/* Encoding of the file mode. */ + +#define __S_IFMT 0170000 /* These bits determine file type. */ + +/* File types. */ +#define __S_IFDIR 0040000 /* Directory. */ +#define __S_IFCHR 0020000 /* Character device. */ +#define __S_IFBLK 0060000 /* Block device. */ +#define __S_IFREG 0100000 /* Regular file. */ +#define __S_IFIFO 0010000 /* FIFO. */ +#define __S_IFLNK 0120000 /* Symbolic link. */ +#define __S_IFSOCK 0140000 /* Socket. */ + +/* Protection bits. */ + +#define __S_ISUID 04000 /* Set user ID on execution. */ +#define __S_ISGID 02000 /* Set group ID on execution. */ +#define __S_ISVTX 01000 /* Save swapped text after use (sticky). */ +#define __S_IREAD 0400 /* Read by owner. */ +#define __S_IWRITE 0200 /* Write by owner. */ +#define __S_IEXEC 0100 /* Execute by owner. */ + +#endif /* statbuf.h */ diff --git a/sysdeps/unix/sysv/linux/powerpc/syscall.S b/sysdeps/unix/sysv/linux/powerpc/syscall.S index 9b3f66682e..441dd5d433 100644 --- a/sysdeps/unix/sysv/linux/powerpc/syscall.S +++ b/sysdeps/unix/sysv/linux/powerpc/syscall.S @@ -28,5 +28,9 @@ ENTRY (syscall) mr 7,8 sc bnslr +#ifdef PIC + b __syscall_error@plt +#else b __syscall_error +#endif PSEUDO_END (syscall) diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h index c08e3d8060..d6d33bf7af 100644 --- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h +++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h @@ -41,13 +41,21 @@ li 0,syscall; \ sc +#ifdef PIC +#define PSEUDO(name, syscall_name, args) \ + .text; \ + ENTRY (name) \ + DO_CALL (SYS_ify (syscall_name)); \ + bnslr; \ + b __syscall_error@plt +#else #define PSEUDO(name, syscall_name, args) \ .text; \ ENTRY (name) \ DO_CALL (SYS_ify (syscall_name)); \ - bnslr; \ + bnslr; \ b __syscall_error - +#endif #define ret /* Nothing (should be 'blr', but never reached). */ #endif /* ASSEMBLER */ diff --git a/sysdeps/unix/sysv/linux/powerpc/termbits.h b/sysdeps/unix/sysv/linux/powerpc/termbits.h index d1b0a3e3cb..4c6073bfc2 100644 --- a/sysdeps/unix/sysv/linux/powerpc/termbits.h +++ b/sysdeps/unix/sysv/linux/powerpc/termbits.h @@ -17,9 +17,7 @@ Boston, MA 02111-1307, USA. */ #ifndef _TERMBITS_H -#define _TERMBITS_H - -#include <linux/posix_types.h> +#define _TERMBITS_H 1 typedef unsigned char cc_t; typedef unsigned int speed_t; @@ -31,14 +29,14 @@ typedef unsigned int tcflag_t; * concerning namespace pollution. */ -#define NCCS 19 +#define NCCS 32 struct termios { tcflag_t c_iflag; /* input mode flags */ tcflag_t c_oflag; /* output mode flags */ tcflag_t c_cflag; /* control mode flags */ tcflag_t c_lflag; /* local mode flags */ - cc_t c_cc[NCCS]; /* control characters */ cc_t c_line; /* line discipline (== c_cc[19]) */ + cc_t c_cc[NCCS]; /* control characters */ speed_t c_ispeed; /* input speed */ speed_t c_ospeed; /* output speed */ }; @@ -219,80 +217,6 @@ struct ltchars { char t_lnextc; }; -#define FIOCLEX _IO('f', 1) -#define FIONCLEX _IO('f', 2) -#define FIOASYNC _IOW('f', 125, int) -#define FIONBIO _IOW('f', 126, int) -#define FIONREAD _IOR('f', 127, int) -#define TIOCINQ FIONREAD - -#define TIOCGETP _IOR('t', 8, struct sgttyb) -#define TIOCSETP _IOW('t', 9, struct sgttyb) -#define TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */ - -#define TIOCSETC _IOW('t', 17, struct tchars) -#define TIOCGETC _IOR('t', 18, struct tchars) -#define TCGETS _IOR('t', 19, struct termios) -#define TCSETS _IOW('t', 20, struct termios) -#define TCSETSW _IOW('t', 21, struct termios) -#define TCSETSF _IOW('t', 22, struct termios) - -#define TCGETA _IOR('t', 23, struct termio) -#define TCSETA _IOW('t', 24, struct termio) -#define TCSETAW _IOW('t', 25, struct termio) -#define TCSETAF _IOW('t', 28, struct termio) - -#define TCSBRK _IO('t', 29) -#define TCXONC _IO('t', 30) -#define TCFLSH _IO('t', 31) - -#define TIOCSWINSZ _IOW('t', 103, struct winsize) -#define TIOCGWINSZ _IOR('t', 104, struct winsize) -#define TIOCSTART _IO('t', 110) /* start output, like ^Q */ -#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */ -#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */ - -#define TIOCGLTC _IOR('t', 116, struct ltchars) -#define TIOCSLTC _IOW('t', 117, struct ltchars) -#define TIOCSPGRP _IOW('t', 118, int) -#define TIOCGPGRP _IOR('t', 119, int) - -#define TIOCEXCL 0x540C -#define TIOCNXCL 0x540D -#define TIOCSCTTY 0x540E - -#define TIOCSTI 0x5412 -#define TIOCMGET 0x5415 -#define TIOCMBIS 0x5416 -#define TIOCMBIC 0x5417 -#define TIOCMSET 0x5418 -#define TIOCGSOFTCAR 0x5419 -#define TIOCSSOFTCAR 0x541A -#define TIOCLINUX 0x541C -#define TIOCCONS 0x541D -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TIOCPKT 0x5420 - -#define TIOCNOTTY 0x5422 -#define TIOCSETD 0x5423 -#define TIOCGETD 0x5424 -#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ - -#define TIOCSERCONFIG 0x5453 -#define TIOCSERGWILD 0x5454 -#define TIOCSERSWILD 0x5455 -#define TIOCGLCKTRMIOS 0x5456 -#define TIOCSLCKTRMIOS 0x5457 -#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ - /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 diff --git a/sysdeps/unix/sysv/linux/readv.c b/sysdeps/unix/sysv/linux/readv.c new file mode 100644 index 0000000000..458e8ffb38 --- /dev/null +++ b/sysdeps/unix/sysv/linux/readv.c @@ -0,0 +1,71 @@ +/* readv supports all Linux kernels >= 2.0. + Copyright (C) 1997 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + read to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stddef.h> +#include <sys/param.h> +#include <sys/uio.h> + +extern ssize_t __syscall_readv __P ((int, __const struct iovec *, int)); + + +/* Not all versions of the kernel support the large number of records. */ +#undef MAX_IOVEC +#ifdef UIO_FASTIOV +# define MAX_IOVEC UIO_FASTIOV +#else +# define MAX_IOVEC 8 /* 8 is a safe number. */ +#endif + + +/* We should deal with kernel which have a smaller UIO_MAXIOV as well + as a very big count. */ +ssize_t +readv (fd, vector, count) + int fd; + const struct iovec *vector; + int count; +{ + int errno_saved = errno; + ssize_t bytes_read; + + bytes_read = __syscall_readv (fd, vector, count); + + if (bytes_read < 0 && errno == EINVAL && count > MAX_IOVEC) + { + int i; + + /* Restore the old error value as if nothing happened. */ + __set_errno (errno_saved); + + bytes_read = 0; + for (i = 0; i < count; i += MAX_IOVEC) + { + ssize_t bytes = __syscall_readv (fd, vector + i, + MIN (count - i, MAX_IOVEC)); + + if (bytes < 0) + return bytes; + + bytes_read += bytes; + } + } + + return bytes_read; +} diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index 4e92f6d35c..f8644c2705 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -56,7 +56,12 @@ setresuid EXTRA setresuid 3 setresuid sigpending - sigpending 1 sigpending sigprocmask - sigprocmask 3 __sigprocmask sigprocmask sigreturn - sigreturn 1 __sigreturn sigreturn +sys_fstat fxstat fstat 2 __syscall_fstat sys_mknod xmknod mknod 3 __syscall_mknod +sys_lstat lxstat lstat 2 __syscall_lstat +sys_readv readv readv 3 __syscall_readv +sys_stat xstat stat 2 __syscall_stat +sys_writev writev writev 3 __syscall_writev sysinfo EXTRA sysinfo 1 sysinfo swapon - swapon 2 swapon umount EXTRA umount 1 __umount umount diff --git a/sysdeps/unix/sysv/linux/writev.c b/sysdeps/unix/sysv/linux/writev.c new file mode 100644 index 0000000000..11afd81d2e --- /dev/null +++ b/sysdeps/unix/sysv/linux/writev.c @@ -0,0 +1,68 @@ +/* writev supports all Linux kernels >= 2.0. + Copyright (C) 1997 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include <errno.h> +#include <stddef.h> +#include <sys/param.h> +#include <sys/uio.h> + +extern ssize_t __syscall_writev __P ((int, const struct iovec *, int)); + +/* Not all versions of the kernel support the large number of records. */ +#undef MAX_IOVEC +#ifdef UIO_FASTIOV +# define MAX_IOVEC UIO_FASTIOV +#else +# define MAX_IOVEC 8 /* 8 is a safe number. */ +#endif + + +/* We should deal with kernel which have a smaller UIO_MAXIOV as well + as a very big count. */ +ssize_t +writev (fd, vector, count) + int fd; + const struct iovec *vector; + int count; +{ + int errno_saved = errno; + ssize_t bytes_written; + + bytes_written = __syscall_writev (fd, vector, count); + + if (bytes_written < 0 && errno == EINVAL && count > MAX_IOVEC) + { + int i; + + /* Restore the old error value as if nothing happened. */ + __set_errno (errno_saved); + + bytes_written = 0; + for (i = 0; i < count; i += MAX_IOVEC) + { + ssize_t bytes = __syscall_writev (fd, vector + i, + MIN (count - i, MAX_IOVEC)); + + if (bytes < 0) + return bytes_written > 0 ? bytes_written : bytes; + } + } + + return bytes_written; +} diff --git a/sysdeps/unix/sysv/sco3.2.4/Dist b/sysdeps/unix/sysv/sco3.2.4/Dist new file mode 100644 index 0000000000..984b473349 --- /dev/null +++ b/sysdeps/unix/sysv/sco3.2.4/Dist @@ -0,0 +1 @@ +__setpgid.c diff --git a/sysdeps/unix/sysv/sysv4/Dist b/sysdeps/unix/sysv/sysv4/Dist index da3d7e58e1..6395064504 100644 --- a/sysdeps/unix/sysv/sysv4/Dist +++ b/sysdeps/unix/sysv/sysv4/Dist @@ -1,2 +1,4 @@ +__getpgid.c +__setpgid.c sysconfig.h siginfo.h |