2005-12-08 Steven Munroe <sjmunroe@us.ibm.com>

Tom Gall <tom_gall@vnet.ibm.com>

	* elf/rtld.c (dl_main): Initialize l_local_scope for sysinfo_map.
	* sysdeps/powerpc/elf/libc-start.c: Move this...
	* sysdeps/unix/sysv/linux/powerpc/libc-start.c: ...to here.
	* sysdeps/powerpc/powerpc32/dl-start.S: Add _dl_main_dispatch label.
	* sysdeps/powerpc/powerpc32/hp-timing.h: New file.
	* sysdeps/unix/sysv/linux/powerpc/Versions: New file.
	* sysdeps/unix/sysv/linux/clock_getres.c: If HAVE_CLOCK_GETRES_VSYSCALL
	is not defined, redefine INTERNAL_VSYSCALL and INLINE_VSYSCALL to
	INTERNAL_SYSCALL and INLINE_SYSCALL respectively.  Otherwise include
	<bits/libc-vdso.h>.  Use INLINE_VSYSCALL and INTERNAL_SYSCALL instead
	of the normal versions throughout the code.
	* sysdeps/unix/sysv/linux/clock_gettime.c: Likewise if
	HAVE_CLOCK_GETTIME_VSYSCALL is defined.
	* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: New file.
	* sysdeps/unix/sysv/linux/powerpc/dl-vdso.c: New file.
	* sysdeps/unix/sysv/linux/powerpc/dl-vdso.h: New file.
	* sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c: Use vDSO.
	* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c: New file.
	* sysdeps/unix/sysv/linux/powerpc/Makefile: Add dl-vdso to routines.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h: Define
	INLINE_VSYSCALL, INTERNAL_VSYSCALL, INTERNAL_SYSCALL_NCS,
	INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK, HAVE_CLOCK_GETRES_VSYSCALL,
	and HAVE_CLOCK_GETTIME_VSYSCALL.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h: Likewise.
This commit is contained in:
Ulrich Drepper 2005-12-30 07:32:48 +00:00
parent 4e54d7e476
commit 8c2e201ba9
16 changed files with 665 additions and 104 deletions

View File

@ -1,3 +1,31 @@
2005-12-08 Steven Munroe <sjmunroe@us.ibm.com>
Tom Gall <tom_gall@vnet.ibm.com>
* elf/rtld.c (dl_main): Initialize l_local_scope for sysinfo_map.
* sysdeps/powerpc/elf/libc-start.c: Move this...
* sysdeps/unix/sysv/linux/powerpc/libc-start.c: ...to here.
* sysdeps/powerpc/powerpc32/dl-start.S: Add _dl_main_dispatch label.
* sysdeps/powerpc/powerpc32/hp-timing.h: New file.
* sysdeps/unix/sysv/linux/powerpc/Versions: New file.
* sysdeps/unix/sysv/linux/clock_getres.c: If HAVE_CLOCK_GETRES_VSYSCALL
is not defined, redefine INTERNAL_VSYSCALL and INLINE_VSYSCALL to
INTERNAL_SYSCALL and INLINE_SYSCALL respectively. Otherwise include
<bits/libc-vdso.h>. Use INLINE_VSYSCALL and INTERNAL_SYSCALL instead
of the normal versions throughout the code.
* sysdeps/unix/sysv/linux/clock_gettime.c: Likewise if
HAVE_CLOCK_GETTIME_VSYSCALL is defined.
* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h: New file.
* sysdeps/unix/sysv/linux/powerpc/dl-vdso.c: New file.
* sysdeps/unix/sysv/linux/powerpc/dl-vdso.h: New file.
* sysdeps/unix/sysv/linux/powerpc/get_clockfreq.c: Use vDSO.
* sysdeps/unix/sysv/linux/powerpc/gettimeofday.c: New file.
* sysdeps/unix/sysv/linux/powerpc/Makefile: Add dl-vdso to routines.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h: Define
INLINE_VSYSCALL, INTERNAL_VSYSCALL, INTERNAL_SYSCALL_NCS,
INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK, HAVE_CLOCK_GETRES_VSYSCALL,
and HAVE_CLOCK_GETTIME_VSYSCALL.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep.h: Likewise.
2005-12-29 Ulrich Drepper <drepper@redhat.com> 2005-12-29 Ulrich Drepper <drepper@redhat.com>
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h [ASSEMBLER]: * sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h [ASSEMBLER]:

View File

@ -1307,6 +1307,13 @@ ld.so does not support TLS, but program uses it!\n");
_dl_setup_hash (l); _dl_setup_hash (l);
l->l_relocated = 1; l->l_relocated = 1;
/* Initialize l_local_scope to contain just this map. This allows
the use of dl_lookup_symbol_x to resolve symbols within the vdso.
So we create a single entry list pointing to l_real as its only
element */
l->l_local_scope[0]->r_nlist = 1;
l->l_local_scope[0]->r_list = &l->l_real;
/* Now that we have the info handy, use the DSO image's soname /* Now that we have the info handy, use the DSO image's soname
so this object can be looked up by name. Note that we do not so this object can be looked up by name. Note that we do not
set l_name here. That field gives the file name of the DSO, set l_name here. That field gives the file name of the DSO,

View File

@ -1,5 +1,5 @@
/* Machine-dependent ELF startup code. PowerPC version. /* Machine-dependent ELF startup code. PowerPC version.
Copyright (C) 1995-2000, 2002, 2004 Free Software Foundation, Inc. Copyright (C) 1995-2000, 2002, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -98,6 +98,7 @@ ENTRY(_dl_start_user)
Take the opportunity to clear LR, so anyone who accidentally returns Take the opportunity to clear LR, so anyone who accidentally returns
from _start gets SEGV. Also clear the next few words of the stack. */ from _start gets SEGV. Also clear the next few words of the stack. */
ENTRY(_dl_main_dispatch)
li r31,0 li r31,0
stw r31,0(r1) stw r31,0(r1)
mtlr r31 mtlr r31

View File

@ -0,0 +1,82 @@
/* High precision, low overhead timing functions. Linux/PPC32 version.
Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _HP_TIMING_H
#define _HP_TIMING_H 1
/* There are no generic definitions for the times. We could write something
using the `gettimeofday' system call where available but the overhead of
the system call might be too high.
In case a platform supports timers in the hardware the following macros
and types must be defined:
- HP_TIMING_AVAIL: test for availability.
- HP_TIMING_INLINE: this macro is non-zero if the functionality is not
implemented using function calls but instead uses some inlined code
which might simply consist of a few assembler instructions. We have to
know this since we might want to use the macros here in places where we
cannot make function calls.
- hp_timing_t: This is the type for variables used to store the time
values.
- HP_TIMING_ZERO: clear `hp_timing_t' object.
- HP_TIMING_NOW: place timestamp for current time in variable given as
parameter.
- HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the
HP_TIMING_DIFF macro.
- HP_TIMING_DIFF: compute difference between two times and store it
in a third. Source and destination might overlap.
- HP_TIMING_ACCUM: add time difference to another variable. This might
be a bit more complicated to implement for some platforms as the
operation should be thread-safe and 64bit arithmetic on 32bit platforms
is not.
- HP_TIMING_ACCUM_NT: this is the variant for situations where we know
there are no threads involved.
- HP_TIMING_PRINT: write decimal representation of the timing value into
the given string. This operation need not be inline even though
HP_TIMING_INLINE is specified.
*/
/* Provide dummy definitions. */
#define HP_TIMING_AVAIL (0)
#define HP_TIMING_INLINE (0)
typedef unsigned long long int hp_timing_t;
#define HP_TIMING_ZERO(Var)
#define HP_TIMING_NOW(var)
#define HP_TIMING_DIFF_INIT()
#define HP_TIMING_DIFF(Diff, Start, End)
#define HP_TIMING_ACCUM(Sum, Diff)
#define HP_TIMING_ACCUM_NT(Sum, Diff)
#define HP_TIMING_PRINT(Buf, Len, Val)
/* Since this implementation is not available we tell the user about it. */
#define HP_TIMING_NONAVAIL 1
#endif /* hp-timing.h */

View File

@ -1,5 +1,5 @@
/* clock_getres -- Get the resolution of a POSIX clockid_t. Linux version. /* clock_getres -- Get the resolution of a POSIX clockid_t. Linux version.
Copyright (C) 2003, 2004 Free Software Foundation, Inc. Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -24,9 +24,17 @@
#include "kernel-features.h" #include "kernel-features.h"
#ifndef HAVE_CLOCK_GETRES_VSYSCALL
# undef INTERNAL_VSYSCALL
# define INTERNAL_VSYSCALL INTERNAL_SYSCALL
# undef INLINE_VSYSCALL
# define INLINE_VSYSCALL INLINE_SYSCALL
#else
# include <bits/libc-vdso.h>
#endif
#define SYSCALL_GETRES \ #define SYSCALL_GETRES \
retval = INLINE_SYSCALL (clock_getres, 2, clock_id, res); \ retval = INLINE_VSYSCALL (clock_getres, 2, clock_id, res); \
break break
#ifdef __ASSUME_POSIX_TIMERS #ifdef __ASSUME_POSIX_TIMERS
@ -52,7 +60,7 @@ maybe_syscall_getres (clockid_t clock_id, struct timespec *res)
if (!__libc_missing_posix_timers) if (!__libc_missing_posix_timers)
{ {
INTERNAL_SYSCALL_DECL (err); INTERNAL_SYSCALL_DECL (err);
int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); int r = INTERNAL_VSYSCALL (clock_getres, err, 2, clock_id, res);
if (!INTERNAL_SYSCALL_ERROR_P (r, err)) if (!INTERNAL_SYSCALL_ERROR_P (r, err))
return 0; return 0;
@ -109,7 +117,7 @@ maybe_syscall_getres_cpu (clockid_t clock_id, struct timespec *res)
if (!__libc_missing_posix_cpu_timers) if (!__libc_missing_posix_cpu_timers)
{ {
INTERNAL_SYSCALL_DECL (err); INTERNAL_SYSCALL_DECL (err);
int r = INTERNAL_SYSCALL (clock_getres, err, 2, clock_id, res); int r = INTERNAL_VSYSCALL (clock_getres, err, 2, clock_id, res);
if (!INTERNAL_SYSCALL_ERROR_P (r, err)) if (!INTERNAL_SYSCALL_ERROR_P (r, err))
return 0; return 0;
@ -128,7 +136,7 @@ maybe_syscall_getres_cpu (clockid_t clock_id, struct timespec *res)
{ {
/* Check whether the kernel supports CPU clocks at all. /* Check whether the kernel supports CPU clocks at all.
If not, record it for the future. */ If not, record it for the future. */
r = INTERNAL_SYSCALL (clock_getres, err, 2, r = INTERNAL_VSYSCALL (clock_getres, err, 2,
MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
NULL); NULL);
if (INTERNAL_SYSCALL_ERROR_P (r, err)) if (INTERNAL_SYSCALL_ERROR_P (r, err))

View File

@ -1,5 +1,5 @@
/* clock_gettime -- Get current time from a POSIX clockid_t. Linux version. /* clock_gettime -- Get current time from a POSIX clockid_t. Linux version.
Copyright (C) 2003, 2004 Free Software Foundation, Inc. Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -23,9 +23,17 @@
#include "kernel-posix-cpu-timers.h" #include "kernel-posix-cpu-timers.h"
#include "kernel-features.h" #include "kernel-features.h"
#ifndef HAVE_CLOCK_GETTIME_VSYSCALL
# undef INTERNAL_VSYSCALL
# define INTERNAL_VSYSCALL INTERNAL_SYSCALL
# undef INLINE_VSYSCALL
# define INLINE_VSYSCALL INLINE_SYSCALL
#else
# include <bits/libc-vdso.h>
#endif
#define SYSCALL_GETTIME \ #define SYSCALL_GETTIME \
retval = INLINE_SYSCALL (clock_gettime, 2, clock_id, tp); \ retval = INLINE_VSYSCALL (clock_gettime, 2, clock_id, tp); \
break break
#ifdef __ASSUME_POSIX_TIMERS #ifdef __ASSUME_POSIX_TIMERS
@ -51,7 +59,7 @@ maybe_syscall_gettime (clockid_t clock_id, struct timespec *tp)
if (!__libc_missing_posix_timers) if (!__libc_missing_posix_timers)
{ {
INTERNAL_SYSCALL_DECL (err); INTERNAL_SYSCALL_DECL (err);
int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp);
if (!INTERNAL_SYSCALL_ERROR_P (r, err)) if (!INTERNAL_SYSCALL_ERROR_P (r, err))
return 0; return 0;
@ -108,7 +116,7 @@ maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
if (!__libc_missing_posix_cpu_timers) if (!__libc_missing_posix_cpu_timers)
{ {
INTERNAL_SYSCALL_DECL (err); INTERNAL_SYSCALL_DECL (err);
int r = INTERNAL_SYSCALL (clock_gettime, err, 2, clock_id, tp); int r = INTERNAL_VSYSCALL (clock_gettime, err, 2, clock_id, tp);
if (!INTERNAL_SYSCALL_ERROR_P (r, err)) if (!INTERNAL_SYSCALL_ERROR_P (r, err))
return 0; return 0;
@ -127,7 +135,7 @@ maybe_syscall_gettime_cpu (clockid_t clock_id, struct timespec *tp)
{ {
/* Check whether the kernel supports CPU clocks at all. /* Check whether the kernel supports CPU clocks at all.
If not, record it for the future. */ If not, record it for the future. */
r = INTERNAL_SYSCALL (clock_getres, err, 2, r = INTERNAL_VSYSCALL (clock_getres, err, 2,
MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED), MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED),
NULL); NULL);
if (INTERNAL_SYSCALL_ERROR_P (r, err)) if (INTERNAL_SYSCALL_ERROR_P (r, err))

View File

@ -6,3 +6,7 @@ endif
ifeq ($(subdir),stdlib) ifeq ($(subdir),stdlib)
gen-as-const-headers += ucontext_i.sym gen-as-const-headers += ucontext_i.sym
endif endif
ifeq ($(subdir),elf)
routines += dl-vdso
endif

View File

@ -0,0 +1,7 @@
libc {
GLIBC_PRIVATE {
__vdso_get_tbfreq;
__vdso_clock_gettime;
__vdso_clock_getres;
}
}

View File

@ -0,0 +1,36 @@
/* Resolve function pointers to VDSO functions.
Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _LIBC_VDSO_H
#define _LIBC_VDSO_H
#ifdef SHARED
extern void *__vdso_gettimeofday;
extern void *__vdso_clock_gettime;
extern void *__vdso_clock_getres;
extern void *__vdso_get_tbfreq;
#endif
#endif /* _LIBC_VDSO_H */

View File

@ -0,0 +1,59 @@
/* ELF symbol resolve functions for VDSO objects.
Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include "config.h"
#include <dl-hash.h>
#include <ldsodefs.h>
void *
internal_function
_dl_vdso_vsym (const char *name, const char *version)
{
struct link_map *map = GLRO (dl_sysinfo_map);
void *value = NULL;
if (map != NULL)
{
/* Use a WEAK REF so we don't error out if the symbol is not found. */
ElfW (Sym) wsym;
memset (&wsym, 0, sizeof (ElfW (Sym)));
wsym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE));
/* Compute hash value to the version string. */
struct r_found_version vers;
vers.name = version;
vers.hidden = 1;
vers.hash = _dl_elf_hash (version);
/* We don't have a specific file where the symbol can be found. */
vers.filename = NULL;
/* Search the scope of the vdso map. */
const ElfW (Sym) *ref = &wsym;
lookup_t result = GLRO (dl_lookup_symbol_x) (name, map, &ref,
map->l_local_scope,
&vers, 0, 0, NULL);
if (ref != NULL)
value = DL_SYMBOL_ADDRESS (result, ref);
}
return value;
}

View File

@ -0,0 +1,27 @@
/* ELF symbol resolve functions for VDSO objects.
Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#ifndef _DL_VDSO_H
#define _DL_VDSO_H 1
/* Functions for resolving symbols in the VDSO link map. */
extern void *_dl_vdso_vsym (const char *name, const char *version)
internal_function attribute_hidden;
#endif /* dl-vdso.h */

View File

@ -22,14 +22,15 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <sysdep.h>
#include <bits/libc-vdso.h>
hp_timing_t hp_timing_t
__get_clockfreq (void) __get_clockfreq (void)
{ {
/* We read the information from the /proc filesystem. /proc/cpuinfo /* We read the information from the /proc filesystem. /proc/cpuinfo
contains at least one line like: contains at least one line like:
timebase : 33333333 timebase : 33333333
We search for this line and convert the number into an integer. */ We search for this line and convert the number into an integer. */
static hp_timing_t timebase_freq; static hp_timing_t timebase_freq;
hp_timing_t result = 0L; hp_timing_t result = 0L;
@ -38,67 +39,78 @@ __get_clockfreq (void)
if (timebase_freq != 0) if (timebase_freq != 0)
return timebase_freq; return timebase_freq;
int fd = open ("/proc/cpuinfo", O_RDONLY); /* If we can use the vDSO to obtain the timebase even better. */
if (__builtin_expect (fd != -1, 1)) #ifdef SHARED
INTERNAL_SYSCALL_DECL (err);
timebase_freq = INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK (get_tbfreq, err, 0);
if (INTERNAL_SYSCALL_ERROR_P (timebase_freq, err)
&& INTERNAL_SYSCALL_ERRNO (timebase_freq, err) == ENOSYS)
#endif
{ {
/* The timebase will be in the 1st 1024 bytes for systems with up int fd = open ("/proc/cpuinfo", O_RDONLY);
to 8 processors. If the first read returns less then 1024
bytes read, we have the whole cpuinfo and can start the scan.
Otherwise we will have to read more to insure we have the
timebase value in the scan. */
char buf[1024];
ssize_t n;
n = read (fd, buf, sizeof (buf)); if (__builtin_expect (fd != -1, 1))
if (n == sizeof (buf))
{ {
/* We are here because the 1st read returned exactly sizeof /* The timebase will be in the 1st 1024 bytes for systems with up
(buf) bytes. This implies that we are not at EOF and may to 8 processors. If the first read returns less then 1024
not have read the timebase value yet. So we need to read bytes read, we have the whole cpuinfo and can start the scan.
more bytes until we know we have EOF. We copy the lower Otherwise we will have to read more to insure we have the
half of buf to the upper half and read sizeof (buf)/2 timebase value in the scan. */
bytes into the lower half of buf and repeat until we char buf[1024];
reach EOF. We can assume that the timebase will be in ssize_t n;
the last 512 bytes of cpuinfo, so two 512 byte half_bufs
will be sufficient to contain the timebase and will n = read (fd, buf, sizeof (buf));
handle the case where the timebase spans the half_buf if (n == sizeof (buf))
boundry. */
const ssize_t half_buf = sizeof (buf) / 2;
while (n >= half_buf)
{ {
memcpy (buf, buf + half_buf, half_buf); /* We are here because the 1st read returned exactly sizeof
n = read (fd, buf + half_buf, half_buf); (buf) bytes. This implies that we are not at EOF and may
} not have read the timebase value yet. So we need to read
if (n >= 0) more bytes until we know we have EOF. We copy the lower
n += half_buf; half of buf to the upper half and read sizeof (buf)/2
} bytes into the lower half of buf and repeat until we
reach EOF. We can assume that the timebase will be in
if (__builtin_expect (n, 1) > 0) the last 512 bytes of cpuinfo, so two 512 byte half_bufs
{ will be sufficient to contain the timebase and will
char *mhz = memmem (buf, n, "timebase", 7); handle the case where the timebase spans the half_buf
boundry. */
if (__builtin_expect (mhz != NULL, 1)) const ssize_t half_buf = sizeof (buf) / 2;
{ while (n >= half_buf)
char *endp = buf + n;
/* Search for the beginning of the string. */
while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n')
++mhz;
while (mhz < endp && *mhz != '\n')
{ {
if (*mhz >= '0' && *mhz <= '9') memcpy (buf, buf + half_buf, half_buf);
{ n = read (fd, buf + half_buf, half_buf);
result *= 10;
result += *mhz - '0';
}
++mhz;
} }
if (n >= 0)
n += half_buf;
} }
timebase_freq = result;
if (__builtin_expect (n, 1) > 0)
{
char *mhz = memmem (buf, n, "timebase", 7);
if (__builtin_expect (mhz != NULL, 1))
{
char *endp = buf + n;
/* Search for the beginning of the string. */
while (mhz < endp && (*mhz < '0' || *mhz > '9')
&& *mhz != '\n')
++mhz;
while (mhz < endp && *mhz != '\n')
{
if (*mhz >= '0' && *mhz <= '9')
{
result *= 10;
result += *mhz - '0';
}
++mhz;
}
}
timebase_freq = result;
}
close (fd);
} }
close (fd);
} }
return timebase_freq; return timebase_freq;

View File

@ -0,0 +1,42 @@
/* Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <sysdep.h>
#include <bp-checks.h>
#include <stddef.h>
#include <sys/time.h>
#include <time.h>
#include <hp-timing.h>
#undef __gettimeofday
#include <bits/libc-vdso.h>
/* Get the current time of day and timezone information,
putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled.
Returns 0 on success, -1 on errors. */
int
__gettimeofday (tv, tz)
struct timeval *tv;
struct timezone *tz;
{
return INLINE_VSYSCALL (gettimeofday, 2, CHECK_1 (tv), CHECK_1 (tz));
}
INTDEF (__gettimeofday)
weak_alias (__gettimeofday, gettimeofday)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1998,2000-2004,2005 Free Software Foundation, Inc. /* Copyright (C) 1998,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -24,33 +24,61 @@
extern int __cache_line_size; extern int __cache_line_size;
weak_extern (__cache_line_size) weak_extern (__cache_line_size)
/* The main work is done in the generic function. */ /* The main work is done in the generic function. */
#define LIBC_START_MAIN generic_start_main #define LIBC_START_MAIN generic_start_main
#define LIBC_START_DISABLE_INLINE #define LIBC_START_DISABLE_INLINE
#define LIBC_START_MAIN_AUXVEC_ARG #define LIBC_START_MAIN_AUXVEC_ARG
#define MAIN_AUXVEC_ARG #define MAIN_AUXVEC_ARG
#define INIT_MAIN_ARGS
#include <csu/libc-start.c> #include <csu/libc-start.c>
struct startup_info struct startup_info
{ {
void *__unbounded sda_base; void *__unbounded sda_base;
int (*main) (int, char **, char **, void *); int (*main) (int, char **, char **, void *);
int (*init) (int, char **, char **, void *); int (*init) (int, char **, char **, void *);
void (*fini) (void); void (*fini) (void);
}; };
#ifdef SHARED
# include <sys/time.h>
# include <dl-vdso.h>
# undef __gettimeofday
# undef __clock_gettime
# undef __clock_getres
# include <bits/libc-vdso.h>
void *__vdso_gettimeofday;
void *__vdso_clock_gettime;
void *__vdso_clock_getres;
void *__vdso_get_tbfreq;
static inline void _libc_vdso_platform_setup (void)
{
__vdso_gettimeofday = _dl_vdso_vsym ("__kernel_gettimeofday",
"LINUX_2.6.15");
__vdso_clock_gettime = _dl_vdso_vsym ("__kernel_clock_gettime",
"LINUX_2.6.15");
__vdso_clock_getres = _dl_vdso_vsym ("__kernel_clock_getres",
"LINUX_2.6.15");
__vdso_get_tbfreq = _dl_vdso_vsym ("__kernel_vdso_get_tbfreq",
"LINUX_2.6.15");
}
#endif
int int
/* GKM FIXME: GCC: this should get __BP_ prefix by virtue of the /* GKM FIXME: GCC: this should get __BP_ prefix by virtue of the
BPs in the arglist of startup_info.main and startup_info.init. */ BPs in the arglist of startup_info.main and startup_info.init. */
BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av, BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av,
char *__unbounded *__unbounded ubp_ev, char *__unbounded *__unbounded ubp_ev,
ElfW(auxv_t) *__unbounded auxvec, ElfW (auxv_t) * __unbounded auxvec,
void (*rtld_fini) (void), void (*rtld_fini) (void),
struct startup_info *__unbounded stinfo, struct startup_info *__unbounded stinfo,
char *__unbounded *__unbounded stack_on_entry) char *__unbounded *__unbounded stack_on_entry)
{ {
#if __BOUNDED_POINTERS__ #if __BOUNDED_POINTERS__
char **argv; char **argv;
@ -60,13 +88,13 @@ BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av,
/* the PPC SVR4 ABI says that the top thing on the stack will /* 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 be a NULL pointer, so if not we assume that we're being called
as a statically-linked program by Linux... */ as a statically-linked program by Linux... */
if (*stack_on_entry != NULL) if (*stack_on_entry != NULL)
{ {
char *__unbounded *__unbounded temp; char *__unbounded * __unbounded temp;
/* ...in which case, we have argc as the top thing on the /* ...in which case, we have argc as the top thing on the
stack, followed by argv (NULL-terminated), envp (likewise), stack, followed by argv (NULL-terminated), envp (likewise),
and the auxilary vector. */ and the auxilary vector. */
/* 32/64-bit agnostic load from stack */ /* 32/64-bit agnostic load from stack */
argc = *(long int *__unbounded) stack_on_entry; argc = *(long int *__unbounded) stack_on_entry;
ubp_av = stack_on_entry + 1; ubp_av = stack_on_entry + 1;
@ -74,25 +102,28 @@ BP_SYM (__libc_start_main) (int argc, char *__unbounded *__unbounded ubp_av,
#ifdef HAVE_AUX_VECTOR #ifdef HAVE_AUX_VECTOR
temp = ubp_ev; temp = ubp_ev;
while (*temp != NULL) while (*temp != NULL)
++temp; ++temp;
auxvec = (ElfW(auxv_t) *)++temp; auxvec = (ElfW (auxv_t) *)++ temp;
#endif #endif
rtld_fini = NULL; rtld_fini = NULL;
} }
/* Initialize the __cache_line_size variable from the aux vector. */ /* Initialize the __cache_line_size variable from the aux vector. */
for (ElfW(auxv_t) *av = auxvec; av->a_type != AT_NULL; ++av) for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
switch (av->a_type) switch (av->a_type)
{ {
case AT_DCACHEBSIZE: case AT_DCACHEBSIZE:
{ {
int *cls = & __cache_line_size; int *cls = &__cache_line_size;
if (cls != NULL) if (cls != NULL)
*cls = av->a_un.a_val; *cls = av->a_un.a_val;
} }
break; break;
} }
#ifdef SHARED
/* Resolve and initialize function pointers for VDSO functions. */
_libc_vdso_platform_setup ();
#endif
return generic_start_main (stinfo->main, argc, ubp_av, auxvec, return generic_start_main (stinfo->main, argc, ubp_av, auxvec,
stinfo->init, stinfo->fini, rtld_fini, stinfo->init, stinfo->fini, rtld_fini,
stack_on_entry); stack_on_entry);

View File

@ -55,6 +55,109 @@
# include <errno.h> # include <errno.h>
# ifdef SHARED
# define INLINE_VSYSCALL(name, nr, args...) \
({ \
__label__ out; \
__label__ iserr; \
INTERNAL_SYSCALL_DECL (sc_err); \
long int sc_ret; \
\
if (__vdso_##name != NULL) \
{ \
sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, sc_err, nr, ##args); \
if (!INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
goto out; \
if (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err) != ENOSYS) \
goto iserr; \
} \
\
sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, ##args); \
if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
{ \
iserr: \
__set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \
sc_ret = -1L; \
} \
out: \
sc_ret; \
})
# else
# define INLINE_VSYSCALL(name, nr, args...) \
INLINE_SYSCALL (name, nr, ##args)
# endif
# ifdef SHARED
# define INTERNAL_VSYSCALL(name, err, nr, args...) \
({ \
__label__ out; \
long int v_ret; \
\
if (__vdso_##name != NULL) \
{ \
v_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
if (!INTERNAL_SYSCALL_ERROR_P (v_ret, err) \
|| INTERNAL_SYSCALL_ERRNO (v_ret, err) != ENOSYS) \
goto out; \
} \
v_ret = INTERNAL_SYSCALL (name, err, nr, ##args); \
out: \
v_ret; \
})
# else
# define INTERNAL_VSYSCALL(name, err, nr, args...) \
INTERNAL_SYSCALL (name, err, nr, ##args)
# endif
# define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \
({ \
long int sc_ret = ENOSYS; \
\
if (__vdso_##name != NULL) \
sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
else \
err = 1 << 28; \
sc_ret; \
})
/* List of system calls which are supported as vsyscalls. */
# define HAVE_CLOCK_GETRES_VSYSCALL 1
# define HAVE_CLOCK_GETTIME_VSYSCALL 1
/* Define a macro which expands inline into the wrapper code for a VDSO
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno.
On powerpc a system call basically clobbers the same registers like a
function call, with the exception of LR (which is needed for the
"sc; bnslr+" sequence) and CR (where only CR0.SO is clobbered to signal
an error return status). */
# define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \
({ \
register void *r0 __asm__ ("r0"); \
register long int r3 __asm__ ("r3"); \
register long int r4 __asm__ ("r4"); \
register long int r5 __asm__ ("r5"); \
register long int r6 __asm__ ("r6"); \
register long int r7 __asm__ ("r7"); \
register long int r8 __asm__ ("r8"); \
register long int r9 __asm__ ("r9"); \
register long int r10 __asm__ ("r10"); \
register long int r11 __asm__ ("r11"); \
register long int r12 __asm__ ("r12"); \
LOADARGS_##nr (funcptr, args); \
__asm__ __volatile__ \
("mtctr %0\n\t" \
"bctrl\n\t" \
"mfcr %0" \
: "=&r" (r0), \
"=&r" (r3), "=&r" (r4), "=&r" (r5), "=&r" (r6), "=&r" (r7), \
"=&r" (r8), "=&r" (r9), "=&r" (r10), "=&r" (r11), "=&r" (r12) \
: ASM_INPUT_##nr \
: "cr0", "ctr", "lr", "memory"); \
err = (long int) r0; \
(int) r3; \
})
# undef INLINE_SYSCALL # undef INLINE_SYSCALL
# define INLINE_SYSCALL(name, nr, args...) \ # define INLINE_SYSCALL(name, nr, args...) \
({ \ ({ \
@ -93,7 +196,7 @@
register long int r10 __asm__ ("r10"); \ register long int r10 __asm__ ("r10"); \
register long int r11 __asm__ ("r11"); \ register long int r11 __asm__ ("r11"); \
register long int r12 __asm__ ("r12"); \ register long int r12 __asm__ ("r12"); \
LOADARGS_##nr(name, args); \ LOADARGS_##nr(name, args); \
__asm__ __volatile__ \ __asm__ __volatile__ \
("sc \n\t" \ ("sc \n\t" \
"mfcr %0" \ "mfcr %0" \
@ -115,11 +218,11 @@
# undef INTERNAL_SYSCALL_ERRNO # undef INTERNAL_SYSCALL_ERRNO
# define INTERNAL_SYSCALL_ERRNO(val, err) (val) # define INTERNAL_SYSCALL_ERRNO(val, err) (val)
# define LOADARGS_0(name, dummy) \ # define LOADARGS_0(name, dummy) \
r0 = name r0 = name
# define LOADARGS_1(name, __arg1) \ # define LOADARGS_1(name, __arg1) \
long int arg1 = (long int) (__arg1); \ long int arg1 = (long int) (__arg1); \
LOADARGS_0(name, 0); \ LOADARGS_0(name, 0); \
extern void __illegally_sized_syscall_arg1 (void); \ extern void __illegally_sized_syscall_arg1 (void); \
if (__builtin_classify_type (__arg1) != 5 && sizeof (__arg1) > 4) \ if (__builtin_classify_type (__arg1) != 5 && sizeof (__arg1) > 4) \
__illegally_sized_syscall_arg1 (); \ __illegally_sized_syscall_arg1 (); \

View File

@ -62,12 +62,118 @@
#ifdef __ASSEMBLER__ #ifdef __ASSEMBLER__
/* This seems to always be the case on PPC. */ /* This seems to always be the case on PPC. */
#define ALIGNARG(log2) log2 # define ALIGNARG(log2) log2
/* For ELF we need the `.type' directive to make shared libs work right. */ /* For ELF we need the `.type' directive to make shared libs work right. */
#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; # define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg;
#define ASM_SIZE_DIRECTIVE(name) .size name,.-name # define ASM_SIZE_DIRECTIVE(name) .size name,.-name
#endif /* __ASSEMBLER__ */ #endif /* __ASSEMBLER__ */
/* This version is for kernels that implement system calls that
behave like function calls as far as register saving.
It falls back to the syscall in the case that the vDSO doesn't
exist or fails for ENOSYS */
#ifdef SHARED
# define INLINE_VSYSCALL(name, nr, args...) \
({ \
__label__ out; \
__label__ iserr; \
INTERNAL_SYSCALL_DECL (sc_err); \
long int sc_ret; \
\
if (__vdso_##name != NULL) \
{ \
sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, sc_err, nr, ##args); \
if (!INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
goto out; \
if (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err) != ENOSYS) \
goto iserr; \
} \
\
sc_ret = INTERNAL_SYSCALL (name, sc_err, nr, ##args); \
if (INTERNAL_SYSCALL_ERROR_P (sc_ret, sc_err)) \
{ \
iserr: \
__set_errno (INTERNAL_SYSCALL_ERRNO (sc_ret, sc_err)); \
sc_ret = -1L; \
} \
out: \
sc_ret; \
})
#else
# define INLINE_VSYSCALL(name, nr, args...) \
INLINE_SYSCALL (name, nr, ##args)
#endif
#ifdef SHARED
# define INTERNAL_VSYSCALL(name, err, nr, args...) \
({ \
__label__ out; \
long int v_ret; \
\
if (__vdso_##name != NULL) \
{ \
v_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
if (!INTERNAL_SYSCALL_ERROR_P (v_ret, err) \
|| INTERNAL_SYSCALL_ERRNO (v_ret, err) != ENOSYS) \
goto out; \
} \
v_ret = INTERNAL_SYSCALL (name, err, nr, ##args); \
out: \
v_ret; \
})
#else
# define INTERNAL_VSYSCALL(name, err, nr, args...) \
INTERNAL_SYSCALL (name, err, nr, ##args)
#endif
/* This version is for internal uses when there is no desire
to set errno */
#define INTERNAL_VSYSCALL_NO_SYSCALL_FALLBACK(name, err, nr, args...) \
({ \
long int sc_ret = ENOSYS; \
\
if (__vdso_##name != NULL) \
sc_ret = INTERNAL_VSYSCALL_NCS (__vdso_##name, err, nr, ##args); \
else \
err = 1 << 28; \
sc_ret; \
})
/* List of system calls which are supported as vsyscalls. */
#define HAVE_CLOCK_GETRES_VSYSCALL 1
#define HAVE_CLOCK_GETTIME_VSYSCALL 1
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno. This returns just what the kernel
gave back in the non-error (CR0.SO cleared) case, otherwise (CR0.SO set)
the negation of the return value in the kernel gets reverted. */
#define INTERNAL_VSYSCALL_NCS(funcptr, err, nr, args...) \
({ \
register void *r0 __asm__ ("r0"); \
register long int r3 __asm__ ("r3"); \
register long int r4 __asm__ ("r4"); \
register long int r5 __asm__ ("r5"); \
register long int r6 __asm__ ("r6"); \
register long int r7 __asm__ ("r7"); \
register long int r8 __asm__ ("r8"); \
LOADARGS_##nr (funcptr, args); \
__asm__ __volatile__ \
("mtctr %0\n\t" \
"bctrl\n\t" \
"mfcr %0\n\t" \
"0:" \
: "=&r" (r0), \
"=&r" (r3), "=&r" (r4), "=&r" (r5), \
"=&r" (r6), "=&r" (r7), "=&r" (r8) \
: ASM_INPUT_##nr \
: "r9", "r10", "r11", "r12", \
"cr0", "ctr", "lr", "memory"); \
err = (long int) r0; \
(int) r3; \
})
#undef INLINE_SYSCALL #undef INLINE_SYSCALL
@ -101,7 +207,7 @@
register long int r6 __asm__ ("r6"); \ register long int r6 __asm__ ("r6"); \
register long int r7 __asm__ ("r7"); \ register long int r7 __asm__ ("r7"); \
register long int r8 __asm__ ("r8"); \ register long int r8 __asm__ ("r8"); \
LOADARGS_##nr(name, args); \ LOADARGS_##nr (name, ##args); \
__asm__ __volatile__ \ __asm__ __volatile__ \
("sc\n\t" \ ("sc\n\t" \
"mfcr %0\n\t" \ "mfcr %0\n\t" \
@ -116,7 +222,7 @@
(int) r3; \ (int) r3; \
}) })
#define INTERNAL_SYSCALL(name, err, nr, args...) \ #define INTERNAL_SYSCALL(name, err, nr, args...) \
INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args) INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, args)
#undef INTERNAL_SYSCALL_DECL #undef INTERNAL_SYSCALL_DECL
#define INTERNAL_SYSCALL_DECL(err) long int err #define INTERNAL_SYSCALL_DECL(err) long int err