Edit

IABSD.fr/src/lib/libc/dlfcn/init.c

Branch :

  • Show log

    Commit

  • Author : naddy
    Date : 2026-05-09 19:39:14
    Hash : 3013aa33
    Message : libc: declare _hwcap and related variables as hidden ok tb@ deraadt@

  • lib/libc/dlfcn/init.c
  • /*	$OpenBSD: init.c,v 1.25 2026/05/09 19:39:14 naddy Exp $ */
    /*
     * Copyright (c) 2014,2015 Philip Guenther <guenther@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    
    #define _DYN_LOADER
    
    #include <sys/types.h>
    #include <sys/syscall.h>
    #include <sys/timetc.h>		/* timekeep */
    #include <sys/auxv.h>		/* _hwcap */
    
    #ifndef PIC
    #include <sys/mman.h>
    #endif
    
    #include <tib.h>
    #include <limits.h>		/* NAME_MAX */
    #include <link.h>
    #include <stdlib.h>		/* atexit */
    #include <string.h>
    #include <unistd.h>
    
    #include "init.h"
    
    #define MAX(a,b)	(((a)>(b))?(a):(b))
    
    #ifdef TIB_EXTRA_ALIGN
    # define TIB_ALIGN	MAX(__alignof__(struct tib), TIB_EXTRA_ALIGN)
    #else
    # define TIB_ALIGN	__alignof__(struct tib)
    #endif
    
    /* XXX should be in an include file shared with csu */
    char	***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
    
    /* provide definitions for these */
    int	_pagesize = 0;
    struct timekeep	*_timekeep;
    unsigned long	_hwcap, _hwcap2;
    int	_hwcap_avail, _hwcap2_avail;
    
    /*
     * In dynamically linked binaries environ and __progname are overridden by
     * the definitions in ld.so.
     */
    char	**environ __attribute__((weak)) = NULL;
    char	*__progname __attribute__((weak)) = NULL;
    
    
    #ifndef PIC
    struct dl_phdr_info	_static_phdr_info __relro = { .dlpi_name = "a.out" };
    
    static inline void early_static_init(char **_argv, char **_envp);
    static inline void setup_static_tib(Elf_Phdr *_phdr, int _phnum);
    
    /* provided by the linker */
    extern Elf_Ehdr __executable_start[] __attribute__((weak));
    #endif /* PIC */
    
    /* provide definitions for these */
    const dl_cb *_dl_cb __relro = NULL;
    
    int	HIDDEN(execve)(const char *, char *const *, char *const *)
    	__attribute__((weak));
    
    void _libc_preinit(int, char **, char **, dl_cb_cb *) __dso_hidden;
    void
    _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
    {
    	AuxInfo	*aux;
    #ifndef PIC
    	Elf_Phdr *phdr = NULL;
    	int phnum = 0;
    
    	/* static libc in a static link? */
    	if (cb == NULL)
    		early_static_init(argv, envp);
    #endif /* !PIC */
    
    	if (cb != NULL)
    		_dl_cb = cb(DL_CB_CUR);
    
    	/* Extract useful bits from the auxiliary vector */
    	while (*envp++ != NULL)
    		;
    	for (aux = (void *)envp; aux->au_id != AUX_null; aux++) {
    		switch (aux->au_id) {
    		case AUX_hwcap:
    			_hwcap = aux->au_v;
    			_hwcap_avail = 1;
    			break;
    		case AUX_hwcap2:
    			_hwcap2 = aux->au_v;
    			_hwcap2_avail = 1;
    			break;
    		case AUX_pagesz:
    			_pagesize = aux->au_v;
    			break;
    #ifndef PIC
    		case AUX_base:
    			_static_phdr_info.dlpi_addr = aux->au_v;
    			break;
    		case AUX_phdr:
    			phdr = (void *)aux->au_v;
    			break;
    		case AUX_phnum:
    			phnum = aux->au_v;
    			break;
    #endif /* !PIC */
    		case AUX_openbsd_timekeep:
    			if (_tc_get_timecount) {
    				_timekeep = (void *)aux->au_v;
    				if (_timekeep &&
    				    _timekeep->tk_version != TK_VERSION)
    					_timekeep = NULL;
    			}
    			if (issetugid() == 0 && getenv("LIBC_NOUSERTC"))
    				_timekeep = NULL;
    			break;
    		}
    	}
    
    #ifndef PIC
    	if (cb == NULL && phdr == NULL && __executable_start != NULL) {
    		/*
    		 * Static non-PIE processes don't get an AUX vector,
    		 * so find the phdrs through the ELF header
    		 */
    		phdr = (void *)((char *)__executable_start +
    		    __executable_start->e_phoff);
    		phnum = __executable_start->e_phnum;
    	}
    	_static_phdr_info.dlpi_phdr = phdr;
    	_static_phdr_info.dlpi_phnum = phnum;
    
    	/* static libc in a static link? */
    	if (cb == NULL)
    		setup_static_tib(phdr, phnum);
    
    	/*
    	 * If a static binary has text relocations (DT_TEXT), then un-writeable
    	 * segments were not made immutable by the kernel.  Textrel and RELRO
    	 * changes have now been completed and permissions corrected, so these
    	 * regions can become immutable.
    	 */
    	if (phdr) {
    		int i;
    
    		for (i = 0; i < phnum; i++) {
    			if (phdr[i].p_type == PT_LOAD &&
    			    (phdr[i].p_flags & PF_W) == 0)
    				mimmutable((void *)(_static_phdr_info.dlpi_addr +
    				    phdr[i].p_vaddr), phdr[i].p_memsz);
    		}
    	}
    #endif /* !PIC */
    }
    
    /* ARM just had to be different... */
    #ifndef __arm__
    # define TYPE	"@"
    #else
    # define TYPE	"%"
    #endif
    
    #ifdef __LP64__
    # define VALUE_ALIGN		".balign 8"
    # define VALUE_DIRECTIVE	".quad"
    #else
    # define VALUE_ALIGN		".balign 4"
    # ifdef __hppa__
       /* hppa just had to be different: func pointers prefix with 'P%' */
    #  define VALUE_DIRECTIVE	".int P%"
    # else
    #  define VALUE_DIRECTIVE	".int"
    # endif
    #endif
    
    #ifdef PIC
    /*
     * Set a priority so _libc_preinit gets called before the constructor
     * on libcompiler_rt that may use elf_aux_info(3).
     */
    __asm(" .section .init_array.50,\"a\","TYPE"init_array\n " \
    	VALUE_ALIGN"\n "VALUE_DIRECTIVE" _libc_preinit\n .previous");
    #else
    __asm(" .section .preinit_array,\"a\","TYPE"preinit_array\n " \
    	VALUE_ALIGN"\n "VALUE_DIRECTIVE" _libc_preinit\n .previous");
    #endif
    
    /*
     * In dynamic links, invoke ld.so's dl_clean_boot() callback, if any,
     * and register its cleanup.
     */
    char ***
    _csu_finish(char **argv, char **envp, void (*cleanup)(void))
    {
    	if (_dl_cb != NULL && _dl_cb->dl_clean_boot != NULL)
    		_dl_cb->dl_clean_boot();
    
    	if (cleanup != NULL)
    		atexit(cleanup);
    
    	return &environ;
    }
    
    #ifndef PIC
    /*
     * static libc in a static link?  Then set up __progname and environ
     */
    static inline void
    early_static_init(char **argv, char **envp)
    {
    	static char progname_storage[NAME_MAX+1];
    
    	environ = envp;
    
    	/* set up __progname */
    	if (*argv != NULL) {		/* NULL ptr if argc = 0 */
    		const char *p = strrchr(*argv, '/');
    
    		if (p == NULL)
    			p = *argv;
    		else
    			p++;
    		strlcpy(progname_storage, p, sizeof(progname_storage));
    	}
    	__progname = progname_storage;
    }
    
    /*
     * static TLS handling
     */
    #define ELF_ROUND(x,malign)	(((x) + (malign)-1) & ~((malign)-1))
    
    /* for static binaries, the location and size of the TLS image */
    static void		*static_tls __relro;
    static size_t		static_tls_fsize __relro;
    
    size_t			_static_tls_size __relro = 0;
    int			_static_tls_align __relro;
    int			_static_tls_align_offset __relro;
    
    static inline void
    setup_static_tib(Elf_Phdr *phdr, int phnum)
    {
    	struct tib *tib;
    	char *base;
    	int i;
    
    	_static_tls_align = TIB_ALIGN;
    	if (phdr != NULL) {
    		for (i = 0; i < phnum; i++) {
    			if (phdr[i].p_type != PT_TLS)
    				continue;
    			if (phdr[i].p_memsz == 0)
    				break;
    			if (phdr[i].p_memsz < phdr[i].p_filesz)
    				break;		/* invalid */
    			if (phdr[i].p_align > getpagesize())
    				break;		/* nope */
    			_static_tls_align = MAX(phdr[i].p_align, TIB_ALIGN);
    #if TLS_VARIANT == 1
    			/*
    			 * Variant 1 places the data after the TIB.  If the
    			 * TLS alignment is larger than the TIB alignment
    			 * then we may need to pad in front of the TIB to
    			 * place the TLS data on the proper alignment.
    			 * Example: p_align=16 sizeof(TIB)=52 align(TIB)=4
    			 * - need to offset the TIB 12 bytes from the start
    			 * - to place ths TLS data at offset 64
    			 */
    			_static_tls_size = phdr[i].p_memsz;
    			_static_tls_align_offset =
    			    ELF_ROUND(sizeof(struct tib), _static_tls_align) -
    			    sizeof(struct tib);
    #elif TLS_VARIANT == 2
    			/*
    			 * Variant 2 places the data before the TIB
    			 * so we need to round up the size to the
    			 * TLS data alignment TIB's alignment.
    			 * Example A: p_memsz=24 p_align=16 align(TIB)=8
    			 * - need to allocate 32 bytes for TLS as compiler
    			 * - will give the first TLS symbol an offset of -32
    			 * Example B: p_memsz=4 p_align=4 align(TIB)=8
    			 * - need to allocate 8 bytes so that the TIB is
    			 * - properly aligned
    			 */
    			_static_tls_size = ELF_ROUND(phdr[i].p_memsz,
    			    phdr[i].p_align);
    			_static_tls_align_offset = ELF_ROUND(_static_tls_size,
    			    _static_tls_align) - _static_tls_size;
    #endif
    			if (phdr[i].p_vaddr != 0 && phdr[i].p_filesz != 0) {
    				static_tls = (void *)phdr[i].p_vaddr +
    				    _static_phdr_info.dlpi_addr;
    				static_tls_fsize = phdr[i].p_filesz;
    			}
    			break;
    		}
    	}
    
    	base = mmap(NULL, _static_tls_size + _static_tls_align_offset
    	    + sizeof *tib, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
    
    	tib = _static_tls_init(base, NULL);
    	tib->tib_tid = getthrid();
    	TCB_SET(TIB_TO_TCB(tib));
    #if ! TCB_HAVE_MD_GET
    	_libc_single_tcb = TIB_TO_TCB(tib);
    #endif
    }
    
    struct tib *
    _static_tls_init(char *base, void *thread)
    {
    	struct tib *tib;
    
    	base += _static_tls_align_offset;
    # if TLS_VARIANT == 1
    	tib = (struct tib *)base;
    	base += sizeof(struct tib);
    # elif TLS_VARIANT == 2
    	tib = (struct tib *)(base + _static_tls_size);
    # endif
    
    	if (_static_tls_size) {
    		if (static_tls != NULL)
    			memcpy(base, static_tls, static_tls_fsize);
    		memset(base + static_tls_fsize, 0,
    		    _static_tls_size - static_tls_fsize);
    	}
    
    	TIB_INIT(tib, NULL, thread);
    	return tib;
    }
    #endif /* !PIC */