Skip to content
This repository has been archived by the owner on Sep 5, 2023. It is now read-only.

Commit

Permalink
Support for dynamic PAGE_SIZE
Browse files Browse the repository at this point in the history
This patch adds support for dynamic PAGE_SIZE values. It
is a little bit invasive in several aspects:

* it modifies the startup code. We need to know the position of
  the elf-info auxilary table which is located after 'environ'.
  We can not use 'environ' directly because it might be modified
  by the application.

  Hence, an additional __elfinfo variable is placed into .bss and
  filled in the startup code. Depending on platform, this adds
  4-8 instructions and an additional pointer to .bss.

  I tested only the i386 and x86_64 modifications; it would be
  nice when people with corresponding hardware would test the
  other ones. I am especially uncertain regarding the parisc
  changes.

  The elf-info stuff (which might be interesting e.g. for dynamic
  linking or sysconf(_SC_CLK_TCK)) can be enabled without the
  dynamic pagesize too.

* it removes the 'PAGE_SIZE' macro from <sys/shm.h>; this will
  break compilation of existing userspace application which are
  using this deprecated macro

* I added a new internal 'dietpagesize.h' header which defines

  | __DIET_PAGE_SIZE
  | __DIET_PAGE_SHIFT

  macros. These return either builtin constants (when
  WANT_DYN_PAGESIZE is not selected), or values derived from
  __libc_getpagesize().

  Every usage of PAGE_SIZE in dietlibc code was replaced by these
  macros.

* due to the previous point, the internal 'struct __dirstream'
  was modified. I replaced

  | getdents64(d->fd,(struct dirent64*)d->buf, sizeof (d->buf)-1);

  with

  | getdents64(d->fd,(struct dirent64*)d->buf,  __DIRSTREAM_BUF_SIZE-1);

  literally but I am not sure where the '-1' is coming from.
  There is one hunk, where this '-1' is missing so I think the
  '-1' should be removed from all calls to getdents64().

* changes affect the *alloc() functions too; on x86_64 around 64
  bytes were added to .text of alloc.o

* the new testprogramm requires a 'getconf' binary which returns
  the correct values for PAGE_SIZE and CLK_TCK

Patch seems to work fine on i386, x86_64, ppc and ppc64.  Things
went a little bit complicated with linux 2.6.25; previous kernels
exported a elf_addr_t type in <linux/elf.h> which is used in the
auxilary elf-info table. Now, this is not available anymore and I
use a type derived from __WORD_SIZE.
  • Loading branch information
ensc committed Apr 6, 2014
1 parent a6f163e commit 6477d31
Show file tree
Hide file tree
Showing 36 changed files with 432 additions and 53 deletions.
9 changes: 9 additions & 0 deletions alpha/start.S
Expand Up @@ -24,6 +24,15 @@ _start:

stq $18, environ

#ifdef WANT_ELFINFO
# warning "MAKE ME alpha ASSEMBLER!"
1: ldq $19, $18 ; load *envp into $19
addq $18, 1, $18 ; increment *envp
orr $19, $19, $19
jne 1b
stq $18, __elfinfo
#endif

#ifdef WANT_DYNAMIC
/* in v0 ($0) is the ld.so _fini pointer */
mov $0, $19 /* mov v0(dynload) to a3 */
Expand Down
27 changes: 26 additions & 1 deletion arm/start.S
Expand Up @@ -13,6 +13,17 @@ FUNC_START _start
add a3, a2, a1, lsl #2 @ &argv[argc]
add a3, a3, #4 @ envp
str a3, [ip, #0] @ environ = envp

#ifdef WANT_ELFINFO
mov r6, a3 @ work on a copy of a3 so that common
@ 'main(argc, argv, envp)' function
@ stays valid
1: ldr r5, [r6], #4 @ load *envp and increment it
cmp r5, #0 @ read value==0?
bne 1b
str r6, [ip, #4] @ __elfinfo = envp
#endif

bl main

@
Expand Down Expand Up @@ -48,11 +59,25 @@ FUNC_START _start
#ifdef __DYN_LIB
ldr sl, .L4
1: add sl, pc, sl
str a3, [sl, ip] @ environ = envp
str a3, [ip, sl]! @ environ = envp; ip = GOT(environ)
#else
str a3, [ip, #0] @ environ = envp
#endif

#ifdef WANT_ELFINFO
mov r6, a3 @ work on a copy of a3 so that common
@ 'main(argc, argv, envp)' function
@ stays valid
1: ldr r5, [r6], #4 @ load *envp and increment it
cmp r5, #0 @ read value==0?
bne 1b
#ifdef __DYN_LIB
str r6, [ip, sl] @ __elfinfo = envp
#else
str r6, [ip, #4] @ __elfinfo = envp
#endif
#endif

#ifdef PROFILING
stmdb sp!, { r0 - r3 }
ldr r0, .L5
Expand Down
6 changes: 5 additions & 1 deletion dietdirent.h
@@ -1,11 +1,13 @@
#include <sys/shm.h>

#include "dietpagesize.h"

struct __dirstream {
char buf[PAGE_SIZE-(sizeof (int)*3)];
int fd;
unsigned int num;
unsigned int cur;
unsigned char is_64;
char buf[] __attribute__((__aligned__(8)));
}; /* stream data from opendir() */

struct linux_dirent {
Expand All @@ -22,3 +24,5 @@ struct linux_dirent64 {
unsigned char d_type;
char d_name[0];
};

#define __DIRSTREAM_BUF_SIZE (__DIET_PAGE_SIZE - offsetof(struct __dirstream, buf))
20 changes: 20 additions & 0 deletions dietelfinfo.h
@@ -0,0 +1,20 @@
#include "dietfeatures.h"

#ifdef WANT_ELFINFO
#include <elf.h>
#include <endian.h>
#include <stdint.h>

/* TODO: exported interface from <linux/elf.h> has been changed in 2.6.25 so
* the 'elf_addr_t' type is not available anymore. Hence, derive it from
* __WORDSIZE__. */

#if __WORDSIZE == 64
typedef uint64_t __diet_elf_addr_t;
#elif __WORDSIZE == 32
typedef uint32_t __diet_elf_addr_t;
#endif

__diet_elf_addr_t const * __get_elf_aux_value(unsigned int tag)
__attribute__((__visibility__("hidden"),__const__)) __pure;
#endif
14 changes: 14 additions & 0 deletions dietfeatures.h
Expand Up @@ -142,6 +142,16 @@
#define WANT_SSP
#endif

/* Some platforms like x86_64, ppc* or mips do not have a fixed PAGE_SIZE.
* Select WANT_DYN_PAGESIZE to detect the current PAGE_SIZE at runtime. Else,
* define WANT_STATIC_PAGESIZE to a proper value (must be a power of 2)
* matching the configured pagesize of the kernel where your binaries are
* running on.
*
* Selecting WANT_DYN_PAGESIZE enlarges the startup code by around 1-3
* instructions and might add an additional __elfinfo symbol */
#define WANT_DYN_PAGESIZE
/* #define WANT_STATIC_PAGESIZE 0x10000UL */


/* stop uncommenting here ;-) */
Expand Down Expand Up @@ -176,4 +186,8 @@
#undef WANT_LARGEFILE_BACKCOMPAT
#endif

#ifdef WANT_DYN_PAGESIZE
#define WANT_ELFINFO
#endif

#endif
31 changes: 31 additions & 0 deletions dietpagesize.h
@@ -0,0 +1,31 @@
#ifndef H_DIETLIBC_DIETPAGESIZE_H
#define H_DIETLIBC_DIETPAGESIZE_H

#include <strings.h>
#include "dietfeatures.h"

extern size_t __libc_getpagesize(void) __attribute__((__const__)) __pure;

#if defined(WANT_STATIC_PAGESIZE)
# define __DIET_PAGE_SIZE_PREDEF (WANT_STATIC_PAGESIZE)
# define __DIET_PAGE_SHIFT_PREDEF (ffs(__DIET_PAGE_SIZE_PREDEF)-1)
#elif defined(__alpha__) || defined(__sparc__)
# define __DIET_PAGE_SIZE_PREDEF (8192UL)
# define __DIET_PAGE_SHIFT_PREDEF (13)
#elif defined(__powerpc64__)
# define __DIET_PAGE_SIZE_PREDEF (65536UL)
# define __DIET_PAGE_SHIFT_PREDEF (16)
#else
# define __DIET_PAGE_SIZE_PREDEF (4096UL)
# define __DIET_PAGE_SHIFT_PREDEF (12)
#endif

#ifdef WANT_DYN_PAGESIZE
# define __DIET_PAGE_SIZE (__libc_getpagesize())
# define __DIET_PAGE_SHIFT (ffs(__DIET_PAGE_SIZE)-1)
#else
# define __DIET_PAGE_SIZE __DIET_PAGE_SIZE_PREDEF
# define __DIET_PAGE_SHIFT __DIET_PAGE_SHIFT_PREDEF
#endif

#endif /* H_DIETLIBC_DIETPAGESIZE_H */
9 changes: 9 additions & 0 deletions dynlinker/ldso_start.S
Expand Up @@ -86,6 +86,15 @@ __environ:
.long 0
#endif

/* __elfinfo must follow __environ immediately */
.global __elfinfo
__elfinfo:
#if __WORDSIZE == 64
.quad 0
#else
.long 0
#endif

.global fini_entry
fini_entry:
.long 0
8 changes: 7 additions & 1 deletion i386/start.S
Expand Up @@ -20,12 +20,18 @@ _start:
PIC_INIT /* non-PIC: this is an empty line */
PUT_VAR %esi, environ, %ecx /* non-PIC: movl %esi,environ */

#ifdef WANT_SYSENTER
#if defined(WANT_ELFINFO) || defined(WANT_SYSENTER)
/* skip environment, scan for NULL */
1:
lodsl
testl %eax,%eax
jnz 1b
# ifdef WANT_ELFINFO
PUT_VAR %esi, __elfinfo, %ecx
# endif
#endif

#ifdef WANT_SYSENTER
/* The ELF auxvec follows the environment, consists of key/value pairs.
We are looking for key 32, which stands for the vsyscall page */
1:
Expand Down
10 changes: 10 additions & 0 deletions ia64/start.S
Expand Up @@ -40,6 +40,16 @@ _start:
;;
st8 [r14] = out2 /* store envp in environ */

#ifdef WANT_ELFINFO
# warning "MAKE ME IE64 CODE!"
1: ld8 r9 = [out2], 8 /* load *envp and increment it */
orr r9 = r9, r9 /* test for NULL */
bne 1b

adds r14 = 8, r14 /* __elfinfo = environ + 8 */
st8 [r14] = out2 /* store envp in __elfinfo */
#endif

#ifdef WANT_DYNAMIC
/* FIXME: dl_init parameter ??? */
br.call.sptk.few rp = _dyn_start
Expand Down
9 changes: 0 additions & 9 deletions include/sys/shm.h
Expand Up @@ -60,15 +60,6 @@ struct shm_info {
unsigned long swap_successes;
};

#if defined(__i386__) || defined(__mips__) || defined(__arm__) || defined(__powerpc__) || defined (__powerpc64__) || defined(__s390__) || defined(__hppa__) || defined(__x86_64__) || defined(__ia64__)
#define PAGE_SIZE 4096UL
#define PAGE_SHIFT 12
#elif defined(__alpha__) || defined(__sparc__)
/* sun4* has 4k except sun4 architecture, sparc64 has 8k */
#define PAGE_SIZE 8192UL
#define PAGE_SHIFT 13
#endif

extern int shmget(key_t key, int size, int shmflg) __THROW;
extern void *shmat(int shmid, const void *shmaddr, int shmflg) __THROW;
extern int shmdt (const void *shmaddr) __THROW;
Expand Down
19 changes: 19 additions & 0 deletions lib/__get_elf_aux_value.c
@@ -0,0 +1,19 @@
#include "dietfeatures.h"

#ifdef WANT_ELFINFO
#include <stdlib.h>
#include "../dietelfinfo.h"

__diet_elf_addr_t const *__get_elf_aux_value(unsigned int tag)
{
extern __diet_elf_addr_t const * const __elfinfo;
__diet_elf_addr_t const *aux_ptr;

for (aux_ptr = __elfinfo; aux_ptr[0]!=AT_NULL; aux_ptr += 2)
if (aux_ptr[0]==tag)
return aux_ptr+1;

return NULL;
}

#endif
9 changes: 5 additions & 4 deletions lib/alloc.c
Expand Up @@ -18,8 +18,7 @@
#include <stdlib.h>
#include <string.h>

#include <sys/shm.h> /* for PAGE_SIZE */

#include "../dietpagesize.h"

/* -- HELPER CODE --------------------------------------------------------- */

Expand All @@ -39,7 +38,7 @@ typedef struct {
#define BLOCK_START(b) (((void*)(b))-sizeof(__alloc_t))
#define BLOCK_RET(b) (((void*)(b))+sizeof(__alloc_t))

#define MEM_BLOCK_SIZE PAGE_SIZE
#define MEM_BLOCK_SIZE __DIET_PAGE_SIZE
#define PAGE_ALIGN(s) (((s)+MEM_BLOCK_SIZE-1)&(unsigned long)(~(MEM_BLOCK_SIZE-1)))

/* a simple mmap :) */
Expand All @@ -66,7 +65,9 @@ static __alloc_t* __small_mem[8];

#define FIRST_SMALL(p) (((unsigned long)(p))&(~(MEM_BLOCK_SIZE-1)))

static inline int __ind_shift() { return (MEM_BLOCK_SIZE==4096)?4:5; }
static inline int __ind_shift() {
return __DIET_PAGE_SHIFT - sizeof(__small_mem)/sizeof(__small_mem[0]);
}

static size_t REGPARM(1) get_index(size_t _size) {
register size_t idx=0;
Expand Down
4 changes: 3 additions & 1 deletion lib/closedir.c
Expand Up @@ -4,8 +4,10 @@
#include <dirent.h>
#include <stdlib.h>

#include "../dietpagesize.h"

int closedir (DIR* d) {
int res=close(d->fd);
munmap (d, PAGE_SIZE);
munmap (d, __DIET_PAGE_SIZE);
return res;
}
3 changes: 2 additions & 1 deletion lib/fdopendir.c
@@ -1,4 +1,5 @@
#include "dietdirent.h"
#include "dietpagesize.h"
#include <sys/mman.h>
#include <unistd.h>
#include <dirent.h>
Expand All @@ -9,7 +10,7 @@ DIR* fdopendir ( int fd ) {
DIR* t = NULL;

if ( fd >= 0 ) {
t = (DIR *) mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
t = (DIR *) mmap (NULL, __DIET_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (t != MAP_FAILED)
t->fd = fd;
Expand Down
6 changes: 4 additions & 2 deletions lib/mmap64.c
Expand Up @@ -4,16 +4,18 @@
#include <syscalls.h>
#include <errno.h>

#include "../dietpagesize.h"

#ifdef __NR_mmap2
void*__mmap2(void*start,size_t length,int prot,int flags,int fd,off_t pgoffset);

void*__libc_mmap64(void*addr,size_t len,int prot,int flags,int fd,off64_t offset);
void*__libc_mmap64(void*addr,size_t len,int prot,int flags,int fd,off64_t offset) {
if (offset&(PAGE_SIZE-1)) {
if (offset&(__DIET_PAGE_SIZE)) {
errno=-EINVAL;
return MAP_FAILED;
}
return __mmap2(addr,len,prot,flags,fd,offset>>PAGE_SHIFT);
return __mmap2(addr,len,prot,flags,fd,offset>>__DIET_PAGE_SHIFT);
}

void*mmap64(void*addr,size_t len,int prot,int flags,int fd,off64_t offset)
Expand Down
4 changes: 3 additions & 1 deletion lib/opendir.c
Expand Up @@ -5,14 +5,16 @@
#include <stdlib.h>
#include <fcntl.h>

#include "../dietpagesize.h"

DIR* opendir ( const char* name ) {
int fd = open (name, O_RDONLY | O_DIRECTORY);
DIR* t = NULL;

if ( fd >= 0 ) {
if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
goto lose;
t = (DIR *) mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
t = (DIR *) mmap (NULL, __DIET_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (t == MAP_FAILED)
lose:
Expand Down
6 changes: 3 additions & 3 deletions lib/readdir64.c
Expand Up @@ -15,7 +15,7 @@
struct dirent64* readdir64(DIR *d) {
struct linux_dirent64 *ld = d->num ? (struct linux_dirent64*)(d->buf+d->cur) : NULL;
if (!d->num || (d->cur += ld->d_reclen)>=d->num) {
int res=getdents64(d->fd,(struct linux_dirent64*)d->buf, sizeof (d->buf)-1);
int res=getdents64(d->fd,(struct linux_dirent64*)d->buf, __DIRSTREAM_BUF_SIZE-1);
if (res<=0) return 0;
d->num=res; d->cur=0; d->is_64=1;
}
Expand All @@ -34,7 +34,7 @@ struct dirent64* readdir64(DIR *d) {
#endif
struct linux_dirent *ld = d->num ? (struct linux_dirent*)(d->buf+d->cur) : NULL;
if (!d->num || (d->cur += ld->d_reclen)>=d->num) {
int res=getdents(d->fd,(struct linux_dirent*)d->buf, sizeof (d->buf)-1);
int res=getdents(d->fd,(struct linux_dirent*)d->buf, __DIRSTREAM_BUF_SIZE-1);
if (res<=0) return 0;
d->num=res; d->cur=0;d->is_64=0;
ld=(struct linux_dirent*)(d->buf+d->cur);
Expand All @@ -50,7 +50,7 @@ struct dirent64* readdir64(DIR *d) {
{
struct linux_dirent64 *ld = d->num ? (struct linux_dirent64*)(d->buf+d->cur) : NULL;
if (!d->num || (d->cur += ld->d_reclen)>=d->num) {
int res=getdents64(d->fd,(struct linux_dirent64*)d->buf,sizeof (d->buf));
int res=getdents64(d->fd,(struct linux_dirent64*)d->buf,__DIRSTREAM_BUF_SIZE);
if (res<=0) {
if (errno==ENOSYS) {
trygetdents64=0;
Expand Down
2 changes: 1 addition & 1 deletion lib/readdir_r.c
Expand Up @@ -8,7 +8,7 @@ int readdir_r(DIR *d,struct dirent* entry, struct dirent** result) {
struct linux_dirent* ld = d->num ? (struct linux_dirent*)(d->buf+d->cur) : NULL;
*result=0;
if (!d->num || d->cur >= d->num || (d->cur += ld->d_reclen)>=d->num) {
int res=getdents(d->fd,(struct linux_dirent*)d->buf,sizeof (d->buf)-1);
int res=getdents(d->fd,(struct linux_dirent*)d->buf,__DIRSTREAM_BUF_SIZE-1);
if (res<=0)
return res<0;
d->num=res; d->cur=0; d->is_64=0;
Expand Down

0 comments on commit 6477d31

Please sign in to comment.