diff options
author | Khem Raj <kraj@mvista.com> | 2008-06-27 04:01:29 +0000 |
---|---|---|
committer | Khem Raj <kraj@mvista.com> | 2008-06-27 04:01:29 +0000 |
commit | d3f9546960f56c05624e2932a899db7f1d38a480 (patch) | |
tree | 6c63cec6c57ad8060a4b6ef983b3b24ece5fc87c | |
parent | da3e789d079c47fea519270269e0c63dd5d497e2 (diff) | |
download | uClibc-alpine-d3f9546960f56c05624e2932a899db7f1d38a480.tar.bz2 uClibc-alpine-d3f9546960f56c05624e2932a899db7f1d38a480.tar.xz |
Sync build machinery stuff from trunk. Some more fixed for mips nptl port
25 files changed, 1467 insertions, 160 deletions
diff --git a/Makefile.in b/Makefile.in index 8fbd45227..8d254722b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -133,13 +133,19 @@ install: install_runtime install_dev RUNTIME_PREFIX_LIB_FROM_DEVEL_PREFIX_LIB=$(shell $(top_srcdir)extra/scripts/relative_path.sh $(DEVEL_PREFIX)lib $(RUNTIME_PREFIX)lib) +$(top_builddir)extra/scripts/unifdef: $(top_srcdir)extra/scripts/unifdef.c + $(hcompile.u) + +# Installs kernel header files (linux/*, asm/*, asm-generic/*). +install_kernel_headers: headers + top_builddir=$(top_builddir) \ + $(top_srcdir)extra/scripts/install_kernel_headers.sh include $(PREFIX)$(DEVEL_PREFIX)include + # Installs header files. -install_headers: headers +install_headers: headers $(top_builddir)extra/scripts/unifdef $(INSTALL) -d $(PREFIX)$(DEVEL_PREFIX)include - printf ".svn\n.cvsignore\nCVS\n" > tar_exclude ; \ - $(TAR) -chf - -X tar_exclude include \ - | $(TAR) -xf - -C $(PREFIX)$(DEVEL_PREFIX) - rm -f tar_exclude + top_builddir=$(top_builddir) \ + $(top_srcdir)extra/scripts/install_headers.sh include $(PREFIX)$(DEVEL_PREFIX)include printf '#ifndef _LIBC_INTERNAL_H\n#define _LIBC_INTERNAL_H 1\n#endif\n' > \ $(PREFIX)$(DEVEL_PREFIX)include/libc-internal.h echo '/* Dont use _syscall#() macros; use the syscall() function */' > \ @@ -230,10 +236,6 @@ ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) # Remove this as it is only used internally. $(RM) $(PREFIX)$(DEVEL_PREFIX)include/tls.h endif - -@for i in `find $(PREFIX)$(DEVEL_PREFIX)include -type d` ; do \ - chmod 755 $$i; chmod 644 $$i/*.h > /dev/null 2>&1; \ - done - -chown -R `id | sed 's/^uid=\([0-9]*\).*gid=\([0-9]*\).*$$/\1:\2/'` $(PREFIX)$(DEVEL_PREFIX)include # Installs development library links. install_dev: install_headers @@ -126,9 +126,9 @@ define link.so $(Q)$(INSTALL) -d $(dir $@) $(Q)$(RM) $@ $@.$(2) $(dir $@)$(1) @$(disp_ld) - $(Q)$(LD) $(LDFLAGS-$(notdir $@)) -soname=$(notdir $@).$(2) \ - -o $(dir $@)$(1) $(START_FILE-$(notdir $@)) \ - --whole-archive $(firstword $^) --no-whole-archive \ + $(Q)$(CC) $(LDFLAGS-$(notdir $@)) -Wl,-soname=$(notdir $@).$(2) \ + -nostdlib -o $(dir $@)$(1) $(START_FILE-$(notdir $@)) \ + -Wl,--whole-archive $(firstword $^) -Wl,--no-whole-archive \ $(LIBS-$(notdir $@)) $(LIBGCC) $(END_FILE-$(notdir $@)) $(Q)$(LN) -sf $(1) $@.$(2) $(Q)$(LN) -sf $(1) $@ @@ -150,10 +150,10 @@ define link-flat.so $(Q)$(INSTALL) -d $(dir $@) $(Q)$(RM) $(1) $@ @$(disp_ld) - $(Q)$(LD) $(LDFLAGS-$(notdir $@)) -o $(1) \ - -elf2flt -shared-lib-id $(2) $(top_builddir)lib/Scrt1.o \ - $(top_builddir)/lib/crti.o --whole-archive $(firstword $^) \ - --no-whole-archive $(LIBS-$(notdir $@)) $(LIBGCC) \ + $(Q)$(CC) $(LDFLAGS-$(notdir $@)) -nostdlib -o $(1) \ + -Wl,-elf2flt -Wl,-shared-lib-id $(2) $(top_builddir)lib/Scrt1.o \ + $(top_builddir)/lib/crti.o -Wl,--whole-archive $(firstword $^) \ + -Wl,--no-whole-archive $(LIBS-$(notdir $@)) $(LIBGCC) \ $(top_builddir)/lib/crtn.o endef @@ -161,8 +161,8 @@ define linkm.so $(Q)$(INSTALL) -d $(dir $@) $(Q)$(RM) $@ $@.$(2) $(dir $@)$(1) @$(disp_ld) - $(Q)$(LD) $(LDFLAGS-$(notdir $@)) -soname=$(notdir $@).$(2) \ - -o $(dir $@)$(1) $(START_FILE-$(notdir $@)) $^ \ + $(Q)$(CC) $(LDFLAGS-$(notdir $@)) -Wl,-soname=$(notdir $@).$(2) \ + -nostdlib -o $(dir $@)$(1) $(START_FILE-$(notdir $@)) $^ \ $(LIBS-$(notdir $@)) $(LIBGCC) $(END_FILE-$(notdir $@)) $(Q)$(LN) -sf $(1) $@.$(2) $(Q)$(LN) -sf $(1) $@ @@ -113,6 +113,9 @@ interp := ldso := endif +comma:=, +space:= # + ifndef CROSS CROSS=$(subst ",, $(strip $(CROSS_COMPILER_PREFIX))) endif @@ -187,8 +190,8 @@ endif ifeq ($(TARGET_ARCH),arm) OPTIMIZATION+=-fstrict-aliasing - CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-EL - CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-EB + CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-Wl,-EL + CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-Wl,-EB CPU_CFLAGS-$(ARCH_LITTLE_ENDIAN)+=-mlittle-endian CPU_CFLAGS-$(ARCH_BIG_ENDIAN)+=-mbig-endian CPU_CFLAGS-$(CONFIG_GENERIC_ARM)+= @@ -209,8 +212,8 @@ ifeq ($(TARGET_ARCH),arm) endif ifeq ($(TARGET_ARCH),mips) - CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-EL - CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-EB + CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-Wl,-EL + CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-Wl,-EB CPU_CFLAGS-$(CONFIG_MIPS_ISA_1)+=-mips1 CPU_CFLAGS-$(CONFIG_MIPS_ISA_2)+=-mips2 -mtune=mips2 CPU_CFLAGS-$(CONFIG_MIPS_ISA_3)+=-mips3 -mtune=mips3 @@ -218,12 +221,12 @@ ifeq ($(TARGET_ARCH),mips) CPU_CFLAGS-$(CONFIG_MIPS_ISA_MIPS32)+=-mips32 -mtune=mips32 CPU_CFLAGS-$(CONFIG_MIPS_ISA_MIPS64)+=-mips64 -mtune=mips32 ifeq ($(strip $(ARCH_BIG_ENDIAN)),y) - CPU_LDFLAGS-$(CONFIG_MIPS_N64_ABI)+=-melf64btsmip - CPU_LDFLAGS-$(CONFIG_MIPS_O32_ABI)+=-melf32btsmip + CPU_LDFLAGS-$(CONFIG_MIPS_N64_ABI)+=-Wl,-melf64btsmip + CPU_LDFLAGS-$(CONFIG_MIPS_O32_ABI)+=-Wl,-melf32btsmip endif ifeq ($(strip $(ARCH_LITTLE_ENDIAN)),y) - CPU_LDFLAGS-$(CONFIG_MIPS_N64_ABI)+=-melf64ltsmip - CPU_LDFLAGS-$(CONFIG_MIPS_O32_ABI)+=-melf32ltsmip + CPU_LDFLAGS-$(CONFIG_MIPS_N64_ABI)+=-Wl,-melf64ltsmip + CPU_LDFLAGS-$(CONFIG_MIPS_O32_ABI)+=-Wl,-melf32ltsmip endif CPU_CFLAGS-$(CONFIG_MIPS_N64_ABI)+=-mabi=64 CPU_CFLAGS-$(CONFIG_MIPS_O32_ABI)+=-mabi=32 @@ -231,15 +234,15 @@ ifeq ($(TARGET_ARCH),mips) endif ifeq ($(TARGET_ARCH),nios) - CPU_LDFLAGS-y+=-m32 - CPU_CFLAGS-y+=-m32 + CPU_LDFLAGS-y+=-Wl,-m32 + CPU_CFLAGS-y+=-Wl,-m32 endif ifeq ($(TARGET_ARCH),sh) OPTIMIZATION+=-fstrict-aliasing OPTIMIZATION+= $(call check_gcc,-mprefergot,) - CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-EL - CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-EB + CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN)+=-Wl,-EL + CPU_LDFLAGS-$(ARCH_BIG_ENDIAN)+=-Wl,-EB CPU_CFLAGS-$(ARCH_LITTLE_ENDIAN)+=-ml CPU_CFLAGS-$(ARCH_BIG_ENDIAN)+=-mb CPU_CFLAGS-$(CONFIG_SH2)+=-m2 @@ -255,23 +258,23 @@ endif ifeq ($(TARGET_ARCH),sh64) OPTIMIZATION+=-fstrict-aliasing - CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN):=-EL - CPU_LDFLAGS-$(ARCH_BIG_ENDIAN):=-EB + CPU_LDFLAGS-$(ARCH_LITTLE_ENDIAN):=-Wl,-EL + CPU_LDFLAGS-$(ARCH_BIG_ENDIAN):=-Wl,-EB CPU_CFLAGS-$(ARCH_LITTLE_ENDIAN):=-ml CPU_CFLAGS-$(ARCH_BIG_ENDIAN):=-mb CPU_CFLAGS-$(CONFIG_SH5)+=-m5-32media endif ifeq ($(TARGET_ARCH),h8300) - CPU_LDFLAGS-$(CONFIG_H8300H)+= -ms8300h - CPU_LDFLAGS-$(CONFIG_H8S) += -ms8300s + CPU_LDFLAGS-$(CONFIG_H8300H)+= -Wl,-ms8300h + CPU_LDFLAGS-$(CONFIG_H8S) += -Wl,-ms8300s CPU_CFLAGS-$(CONFIG_H8300H) += -mh -mint32 CPU_CFLAGS-$(CONFIG_H8S) += -ms -mint32 endif ifeq ($(TARGET_ARCH),cris) - CPU_LDFLAGS-$(CONFIG_CRIS)+=-mcrislinux - CPU_LDFLAGS-$(CONFIG_CRISV32)+=-mcrislinux + CPU_LDFLAGS-$(CONFIG_CRIS)+=-Wl,-mcrislinux + CPU_LDFLAGS-$(CONFIG_CRISV32)+=-Wl,-mcrislinux CPU_CFLAGS-$(CONFIG_CRIS)+=-mlinux PICFLAG:=-fpic PIEFLAG_NAME:=-fpie @@ -295,13 +298,13 @@ ifeq ($(TARGET_ARCH),powerpc) endif ifeq ($(TARGET_ARCH),frv) - CPU_LDFLAGS-$(CONFIG_FRV)+=-melf32frvfd + CPU_LDFLAGS-$(CONFIG_FRV)+=-Wl,-melf32frvfd # Using -pie causes the program to have an interpreter, which is # forbidden, so we must make do with -shared. Unfortunately, # -shared by itself would get us global function descriptors # and calls through PLTs, dynamic resolution of symbols, etc, # which would break as well, but -Bsymbolic comes to the rescue. - export LDPIEFLAG:=-shared -Bsymbolic + export LDPIEFLAG:=-Wl,-shared -Wl,-Bsymbolic UCLIBC_LDSO=ld.so.1 endif @@ -396,16 +399,17 @@ endif # only i386 is known to work if compile.S gets -D__ASSEMBLER__ #CFLAGS += $(call check_gcc,-std=c99,) -LDFLAGS_NOSTRIP:=$(CPU_LDFLAGS-y) -shared --warn-common --warn-once -z combreloc +LDFLAGS_NOSTRIP:=$(CPU_LDFLAGS-y) -Wl,-shared \ + -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc # binutils-2.16.1 warns about ignored sections, 2.16.91.0.3 and newer are ok #LDFLAGS_NOSTRIP+=$(call check_ld,--gc-sections) ifeq ($(UCLIBC_BUILD_RELRO),y) -LDFLAGS_NOSTRIP+=-z relro +LDFLAGS_NOSTRIP+=-Wl,-z,relro endif ifeq ($(UCLIBC_BUILD_NOW),y) -LDFLAGS_NOSTRIP+=-z now +LDFLAGS_NOSTRIP+=-Wl,-z,now endif ifeq ($(LDSO_GNU_HASH_SUPPORT),y) @@ -418,7 +422,7 @@ LDFLAGS_NOSTRIP += $(LDFLAGS_GNUHASH) endif endif -LDFLAGS:=$(LDFLAGS_NOSTRIP) -z defs +LDFLAGS:=$(LDFLAGS_NOSTRIP) -Wl,-z,defs ifeq ($(DODEBUG),y) #CFLAGS += -g3 @@ -427,7 +431,7 @@ else CFLAGS += $(OPTIMIZATION) $(XARCH_CFLAGS) -DNDEBUG endif ifeq ($(DOSTRIP),y) -LDFLAGS += -s +LDFLAGS += -Wl,-s else STRIPTOOL := true -Stripping_disabled endif diff --git a/extra/scripts/gen_bits_syscall_h.sh b/extra/scripts/gen_bits_syscall_h.sh index 116534ab3..c0b4c25f5 100755 --- a/extra/scripts/gen_bits_syscall_h.sh +++ b/extra/scripts/gen_bits_syscall_h.sh @@ -8,9 +8,10 @@ # June 27, 2001 Manuel Novoa III # -# This script expects top_builddir and CC (as used in the Makefiles) to be set in -# the environment, and outputs the appropriate $top_builddir/include/bits/sysnum.h -# corresponding to $top_builddir/include/asm/unistd.h to stdout. +# This script expects top_builddir and CC (as used in the Makefiles) to be set +# in the environment, and outputs the appropriate +# $top_builddir/include/bits/sysnum.h # corresponding to +# $top_builddir/include/asm/unistd.h to stdout. # # Warning!!! This does _no_ error checking!!! @@ -28,7 +29,8 @@ esac -e 's/^[ ]*#undef[ ]*__NR_\([A-Za-z0-9_]*\).*/UNDEFUCLIBC_\1 __NR_\1/gp' # needed to strip out any kernel-internal defines ) | $CC -E $INCLUDE_OPTS - | -( echo "/* WARNING!!! AUTO-GENERATED FILE!!! DO NOT EDIT!!! */" ; echo ; +( echo "/* WARNING!!! AUTO-GENERATED FILE!!! DO NOT EDIT!!! */" ; + echo ; echo "#ifndef _BITS_SYSNUM_H" ; echo "#define _BITS_SYSNUM_H" ; echo ; diff --git a/extra/scripts/install_headers.sh b/extra/scripts/install_headers.sh new file mode 100755 index 000000000..6d73ad2c6 --- /dev/null +++ b/extra/scripts/install_headers.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# Parameters: +# $1 = source dir +# $2 = dst dir +# $top_builddir = well you guessed it + +die_if_not_dir() +{ + for dir in "$@"; do + test -d "$dir" && continue + echo "Error: '$dir' is not a directory" + exit 1 + done +} + + +# Ensure that created dirs/files have 755/644 perms +umask 022 + + +# Sanity tests +die_if_not_dir "$1" +mkdir -p "$2" 2>/dev/null +die_if_not_dir "$2" +die_if_not_dir "$top_builddir" +if ! test -x "$top_builddir/extra/scripts/unifdef"; then + echo "Error: need '$top_builddir/extra/scripts/unifdef' executable" + exit 1 +fi + + +# Sanitize and copy uclibc headers +( +# We must cd, or else we'll prepend "$1" to filenames! +cd "$1" || exit 1 +find ! -name '.' -a ! -path '*/.*' +) | \ +( +IFS='' +while read -r filename; do + filename="${filename#./}" + if test -d "$1/$filename"; then + mkdir -p "$2/$filename" 2>/dev/null + else + # NB: unifdef exits with 1 if output is not + # exactly the same as input. That's ok. + # Do not abort the script if unifdef "fails"! + "$top_builddir/extra/scripts/unifdef" -UUCLIBC_INTERNAL "$1/$filename" \ + | grep -v '^libc_hidden_proto[ ]*([a-zA-Z0-9_]*)$' >"$2/$filename" + fi +done +) + + +# Fix mode/owner bits +cd "$2" || exit 1 +chmod -R u=rwX,go=rX . >/dev/null 2>&1 +chown -R `id | sed 's/^uid=\([0-9]*\).*gid=\([0-9]*\).*$/\1:\2/'` . >/dev/null 2>&1 diff --git a/extra/scripts/install_kernel_headers.sh b/extra/scripts/install_kernel_headers.sh new file mode 100755 index 000000000..7e86eb850 --- /dev/null +++ b/extra/scripts/install_kernel_headers.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# Parameters: +# $1 = source dir +# $2 = dst dir +# $top_builddir = well you guessed it + +die_if_not_dir() +{ + for dir in "$@"; do + test -d "$dir" && continue + echo "Error: '$dir' is not a directory" + exit 1 + done +} + + +# Ensure that created dirs/files have 755/644 perms +umask 022 + + +# Sanity tests +die_if_not_dir "$1" +mkdir -p "$2" 2>/dev/null +die_if_not_dir "$2" +die_if_not_dir "$top_builddir" + + +# Just copy (no sanitization) some kernel headers. +eval `grep ^KERNEL_HEADERS "$top_builddir/.config"` +if ! test "$KERNEL_HEADERS" \ +|| ! test -d "$KERNEL_HEADERS/asm" \ +|| ! test -d "$KERNEL_HEADERS/asm-generic" \ +|| ! test -d "$KERNEL_HEADERS/linux" \ +; then + echo "Error: '$KERNEL_HEADERS' is not a directory containing kernel headers." + echo "Check KERNEL_HEADERS= in your .config file." + exit 1 +fi +# Do the copying only if src and dst dirs are not the same. +# Be thorough: do not settle just for textual compare, +# and guard against "pwd" being handled as shell builtin. +# Double quoting looks weird, but it works (even bbox ash too). +if test "`(cd "$KERNEL_HEADERS"; env pwd)`" != "`(cd "$2"; env pwd)`"; then + # NB: source or target files and directories may be symlinks, + # and for all we know, good reasons. + # We must work correctly in these cases. This includes "do not replace + # target symlink with real directory" rule. So, no rm -rf here please. + mkdir -p "$2/asm" 2>/dev/null + mkdir -p "$2/linux" 2>/dev/null + # Exists, but is not a dir? That's bad, bail out + die_if_not_dir "$2/asm" "$2/linux" + # cp -HL creates regular destination files even if sources are symlinks. + # This is intended. + # (NB: you need busybox 1.11.x for this. earlier ones are slightly buggy) + cp -RHL "$KERNEL_HEADERS/asm"/* "$2/asm" || exit 1 + cp -RHL "$KERNEL_HEADERS/linux"/* "$2/linux" || exit 1 + # Linux 2.4 doesn't have it + if test -d "$KERNEL_HEADERS/asm-generic"; then + mkdir -p "$2/asm-generic" 2>/dev/null + die_if_not_dir "$2/asm-generic" + cp -RHL "$KERNEL_HEADERS/asm-generic"/* "$2/asm-generic" || exit 1 + fi + if ! test -f "$2/linux/version.h"; then + echo "Warning: '$KERNEL_HEADERS/linux/version.h' is not found" + echo "in kernel headers directory specified in .config." + echo "Some programs won't like that. Consider fixing it by hand." + fi +fi + + +# Fix mode/owner bits +cd "$2" || exit 1 +chmod -R u=rwX,go=rX . >/dev/null 2>&1 +chown -R `id | sed 's/^uid=\([0-9]*\).*gid=\([0-9]*\).*$/\1:\2/'` . >/dev/null 2>&1 diff --git a/extra/scripts/unifdef.c b/extra/scripts/unifdef.c new file mode 100644 index 000000000..552025e72 --- /dev/null +++ b/extra/scripts/unifdef.c @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>. All rights reserved. + * + * This code is derived from software contributed to Berkeley by Dave Yost. + * It was rewritten to support ANSI C by Tony Finch. The original version of + * unifdef carried the following copyright notice. None of its code remains + * in this version (though some of the names remain). + * + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#ifndef lint +#if 0 +static const char copyright[] = +"@(#) Copyright (c) 1985, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif +#ifdef __IDSTRING +__IDSTRING(Berkeley, "@(#)unifdef.c 8.1 (Berkeley) 6/6/93"); +__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $"); +__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.171 2005/03/08 12:38:48 fanf2 Exp $"); +#endif +#endif /* not lint */ +#ifdef __FBSDID +__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05/21 09:55:09 ru Exp $"); +#endif + +/* + * unifdef - remove ifdef'ed lines + * + * Wishlist: + * provide an option which will append the name of the + * appropriate symbol after #else's and #endif's + * provide an option which will check symbols after + * #else's and #endif's to see that they match their + * corresponding #ifdef or #ifndef + * + * The first two items above require better buffer handling, which would + * also make it possible to handle all "dodgy" directives correctly. + */ + +#include <ctype.h> +#include <err.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +size_t strlcpy(char *dst, const char *src, size_t siz); + +/* types of input lines: */ +typedef enum { + LT_TRUEI, /* a true #if with ignore flag */ + LT_FALSEI, /* a false #if with ignore flag */ + LT_IF, /* an unknown #if */ + LT_TRUE, /* a true #if */ + LT_FALSE, /* a false #if */ + LT_ELIF, /* an unknown #elif */ + LT_ELTRUE, /* a true #elif */ + LT_ELFALSE, /* a false #elif */ + LT_ELSE, /* #else */ + LT_ENDIF, /* #endif */ + LT_DODGY, /* flag: directive is not on one line */ + LT_DODGY_LAST = LT_DODGY + LT_ENDIF, + LT_PLAIN, /* ordinary line */ + LT_EOF, /* end of file */ + LT_COUNT +} Linetype; + +static char const * const linetype_name[] = { + "TRUEI", "FALSEI", "IF", "TRUE", "FALSE", + "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF", + "DODGY TRUEI", "DODGY FALSEI", + "DODGY IF", "DODGY TRUE", "DODGY FALSE", + "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE", + "DODGY ELSE", "DODGY ENDIF", + "PLAIN", "EOF" +}; + +/* state of #if processing */ +typedef enum { + IS_OUTSIDE, + IS_FALSE_PREFIX, /* false #if followed by false #elifs */ + IS_TRUE_PREFIX, /* first non-false #(el)if is true */ + IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */ + IS_FALSE_MIDDLE, /* a false #elif after a pass state */ + IS_TRUE_MIDDLE, /* a true #elif after a pass state */ + IS_PASS_ELSE, /* an else after a pass state */ + IS_FALSE_ELSE, /* an else after a true state */ + IS_TRUE_ELSE, /* an else after only false states */ + IS_FALSE_TRAILER, /* #elifs after a true are false */ + IS_COUNT +} Ifstate; + +static char const * const ifstate_name[] = { + "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX", + "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE", + "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE", + "FALSE_TRAILER" +}; + +/* state of comment parser */ +typedef enum { + NO_COMMENT = false, /* outside a comment */ + C_COMMENT, /* in a comment like this one */ + CXX_COMMENT, /* between // and end of line */ + STARTING_COMMENT, /* just after slash-backslash-newline */ + FINISHING_COMMENT, /* star-backslash-newline in a C comment */ + CHAR_LITERAL, /* inside '' */ + STRING_LITERAL /* inside "" */ +} Comment_state; + +static char const * const comment_name[] = { + "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING" +}; + +/* state of preprocessor line parser */ +typedef enum { + LS_START, /* only space and comments on this line */ + LS_HASH, /* only space, comments, and a hash */ + LS_DIRTY /* this line can't be a preprocessor line */ +} Line_state; + +static char const * const linestate_name[] = { + "START", "HASH", "DIRTY" +}; + +/* + * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1 + */ +#define MAXDEPTH 64 /* maximum #if nesting */ +#define MAXLINE 4096 /* maximum length of line */ +#define MAXSYMS 4096 /* maximum number of symbols */ + +/* + * Sometimes when editing a keyword the replacement text is longer, so + * we leave some space at the end of the tline buffer to accommodate this. + */ +#define EDITSLOP 10 + +/* + * Globals. + */ + +static bool complement; /* -c: do the complement */ +static bool debugging; /* -d: debugging reports */ +static bool iocccok; /* -e: fewer IOCCC errors */ +static bool killconsts; /* -k: eval constant #ifs */ +static bool lnblank; /* -l: blank deleted lines */ +static bool lnnum; /* -n: add #line directives */ +static bool symlist; /* -s: output symbol list */ +static bool text; /* -t: this is a text file */ + +static const char *symname[MAXSYMS]; /* symbol name */ +static const char *value[MAXSYMS]; /* -Dsym=value */ +static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */ +static int nsyms; /* number of symbols */ + +static FILE *input; /* input file pointer */ +static const char *filename; /* input file name */ +static int linenum; /* current line number */ + +static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ +static char *keyword; /* used for editing #elif's */ + +static Comment_state incomment; /* comment parser state */ +static Line_state linestate; /* #if line parser state */ +static Ifstate ifstate[MAXDEPTH]; /* #if processor state */ +static bool ignoring[MAXDEPTH]; /* ignore comments state */ +static int stifline[MAXDEPTH]; /* start of current #if */ +static int depth; /* current #if nesting */ +static int delcount; /* count of deleted lines */ +static bool keepthis; /* don't delete constant #if */ + +static int exitstat; /* program exit status */ + +static void addsym(bool, bool, char *); +static void debug(const char *, ...); +static void done(void); +static void error(const char *); +static int findsym(const char *); +static void flushline(bool); +static Linetype getline(void); +static Linetype ifeval(const char **); +static void ignoreoff(void); +static void ignoreon(void); +static void keywordedit(const char *); +static void nest(void); +static void process(void); +static const char *skipcomment(const char *); +static const char *skipsym(const char *); +static void state(Ifstate); +static int strlcmp(const char *, const char *, size_t); +static void unnest(void); +static void usage(void); + +#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_') + +/* + * The main program. + */ +int +main(int argc, char *argv[]) +{ + int opt; + + while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1) + switch (opt) { + case 'i': /* treat stuff controlled by these symbols as text */ + /* + * For strict backwards-compatibility the U or D + * should be immediately after the -i but it doesn't + * matter much if we relax that requirement. + */ + opt = *optarg++; + if (opt == 'D') + addsym(true, true, optarg); + else if (opt == 'U') + addsym(true, false, optarg); + else + usage(); + break; + case 'D': /* define a symbol */ + addsym(false, true, optarg); + break; + case 'U': /* undef a symbol */ + addsym(false, false, optarg); + break; + case 'I': + /* no-op for compatibility with cpp */ + break; + case 'c': /* treat -D as -U and vice versa */ + complement = true; + break; + case 'd': + debugging = true; + break; + case 'e': /* fewer errors from dodgy lines */ + iocccok = true; + break; + case 'k': /* process constant #ifs */ + killconsts = true; + break; + case 'l': /* blank deleted lines instead of omitting them */ + lnblank = true; + break; + case 'n': /* add #line directive after deleted lines */ + lnnum = true; + break; + case 's': /* only output list of symbols that control #ifs */ + symlist = true; + break; + case 't': /* don't parse C comments */ + text = true; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + if (argc > 1) { + errx(2, "can only do one file"); + } else if (argc == 1 && strcmp(*argv, "-") != 0) { + filename = *argv; + input = fopen(filename, "r"); + if (input == NULL) + err(2, "can't open %s", filename); + } else { + filename = "[stdin]"; + input = stdin; + } + process(); + abort(); /* bug */ +} + +static void +usage(void) +{ + fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]" + " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n"); + exit(2); +} + +/* + * A state transition function alters the global #if processing state + * in a particular way. The table below is indexed by the current + * processing state and the type of the current line. + * + * Nesting is handled by keeping a stack of states; some transition + * functions increase or decrease the depth. They also maintain the + * ignore state on a stack. In some complicated cases they have to + * alter the preprocessor directive, as follows. + * + * When we have processed a group that starts off with a known-false + * #if/#elif sequence (which has therefore been deleted) followed by a + * #elif that we don't understand and therefore must keep, we edit the + * latter into a #if to keep the nesting correct. + * + * When we find a true #elif in a group, the following block will + * always be kept and the rest of the sequence after the next #elif or + * #else will be discarded. We edit the #elif into a #else and the + * following directive to #endif since this has the desired behaviour. + * + * "Dodgy" directives are split across multiple lines, the most common + * example being a multi-line comment hanging off the right of the + * directive. We can handle them correctly only if there is no change + * from printing to dropping (or vice versa) caused by that directive. + * If the directive is the first of a group we have a choice between + * failing with an error, or passing it through unchanged instead of + * evaluating it. The latter is not the default to avoid questions from + * users about unifdef unexpectedly leaving behind preprocessor directives. + */ +typedef void state_fn(void); + +/* report an error */ +static void Eelif (void) { error("Inappropriate #elif"); } +static void Eelse (void) { error("Inappropriate #else"); } +static void Eendif(void) { error("Inappropriate #endif"); } +static void Eeof (void) { error("Premature EOF"); } +static void Eioccc(void) { error("Obfuscated preprocessor control line"); } +/* plain line handling */ +static void print (void) { flushline(true); } +static void drop (void) { flushline(false); } +/* output lacks group's start line */ +static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); } +static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); } +static void Selse (void) { drop(); state(IS_TRUE_ELSE); } +/* print/pass this block */ +static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); } +static void Pelse (void) { print(); state(IS_PASS_ELSE); } +static void Pendif(void) { print(); unnest(); } +/* discard this block */ +static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); } +static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); } +static void Delse (void) { drop(); state(IS_FALSE_ELSE); } +static void Dendif(void) { drop(); unnest(); } +/* first line of group */ +static void Fdrop (void) { nest(); Dfalse(); } +static void Fpass (void) { nest(); Pelif(); } +static void Ftrue (void) { nest(); Strue(); } +static void Ffalse(void) { nest(); Sfalse(); } +/* variable pedantry for obfuscated lines */ +static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); } +static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); } +static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); } +/* ignore comments in this block */ +static void Idrop (void) { Fdrop(); ignoreon(); } +static void Itrue (void) { Ftrue(); ignoreon(); } +static void Ifalse(void) { Ffalse(); ignoreon(); } +/* edit this line */ +static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); } +static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); } +static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); } +static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); } + +static state_fn * const trans_table[IS_COUNT][LT_COUNT] = { +/* IS_OUTSIDE */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif, + print, done }, +/* IS_FALSE_PREFIX */ +{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif, + Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc, + drop, Eeof }, +/* IS_TRUE_PREFIX */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, + print, Eeof }, +/* IS_PASS_MIDDLE */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif, + print, Eeof }, +/* IS_FALSE_MIDDLE */ +{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif, + Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, + drop, Eeof }, +/* IS_TRUE_MIDDLE */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif, + print, Eeof }, +/* IS_PASS_ELSE */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif, + print, Eeof }, +/* IS_FALSE_ELSE */ +{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif, + Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc, + drop, Eeof }, +/* IS_TRUE_ELSE */ +{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif, + Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc, + print, Eeof }, +/* IS_FALSE_TRAILER */ +{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif, + Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc, + drop, Eeof } +/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF + TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY) + PLAIN EOF */ +}; + +/* + * State machine utility functions + */ +static void +done(void) +{ + if (incomment) + error("EOF in comment"); + exit(exitstat); +} +static void +ignoreoff(void) +{ + if (depth == 0) + abort(); /* bug */ + ignoring[depth] = ignoring[depth-1]; +} +static void +ignoreon(void) +{ + ignoring[depth] = true; +} +static void +keywordedit(const char *replacement) +{ + size_t size = tline + sizeof(tline) - keyword; + char *dst = keyword; + const char *src = replacement; + if (size != 0) { + while ((--size != 0) && (*src != '\0')) + *dst++ = *src++; + *dst = '\0'; + } + print(); +} +static void +nest(void) +{ + depth += 1; + if (depth >= MAXDEPTH) + error("Too many levels of nesting"); + stifline[depth] = linenum; +} +static void +unnest(void) +{ + if (depth == 0) + abort(); /* bug */ + depth -= 1; +} +static void +state(Ifstate is) +{ + ifstate[depth] = is; +} + +/* + * Write a line to the output or not, according to command line options. + */ +static void +flushline(bool keep) +{ + if (symlist) + return; + if (keep ^ complement) { + if (lnnum && delcount > 0) + printf("#line %d\n", linenum); + fputs(tline, stdout); + delcount = 0; + } else { + if (lnblank) + putc('\n', stdout); + exitstat = 1; + delcount += 1; + } +} + +/* + * The driver for the state machine. + */ +static void +process(void) +{ + Linetype lineval; + + for (;;) { + linenum++; + lineval = getline(); + trans_table[ifstate[depth]][lineval](); + debug("process %s -> %s depth %d", + linetype_name[lineval], + ifstate_name[ifstate[depth]], depth); + } +} + +/* + * Parse a line and determine its type. We keep the preprocessor line + * parser state between calls in the global variable linestate, with + * help from skipcomment(). + */ +static Linetype +getline(void) +{ + const char *cp; + int cursym; + int kwlen; + Linetype retval; + Comment_state wascomment; + + if (fgets(tline, MAXLINE, input) == NULL) + return (LT_EOF); + retval = LT_PLAIN; + wascomment = incomment; + cp = skipcomment(tline); + if (linestate == LS_START) { + if (*cp == '#') { + linestate = LS_HASH; + cp = skipcomment(cp + 1); + } else if (*cp != '\0') + linestate = LS_DIRTY; + } + if (!incomment && linestate == LS_HASH) { + keyword = tline + (cp - tline); + cp = skipsym(cp); + kwlen = cp - keyword; + /* no way can we deal with a continuation inside a keyword */ + if (strncmp(cp, "\\\n", 2) == 0) + Eioccc(); + if (strlcmp("ifdef", keyword, kwlen) == 0 || + strlcmp("ifndef", keyword, kwlen) == 0) { + cp = skipcomment(cp); + if ((cursym = findsym(cp)) < 0) + retval = LT_IF; + else { + retval = (keyword[2] == 'n') + ? LT_FALSE : LT_TRUE; + if (value[cursym] == NULL) + retval = (retval == LT_TRUE) + ? LT_FALSE : LT_TRUE; + if (ignore[cursym]) + retval = (retval == LT_TRUE) + ? LT_TRUEI : LT_FALSEI; + } + cp = skipsym(cp); + } else if (strlcmp("if", keyword, kwlen) == 0) + retval = ifeval(&cp); + else if (strlcmp("elif", keyword, kwlen) == 0) + retval = ifeval(&cp) - LT_IF + LT_ELIF; + else if (strlcmp("else", keyword, kwlen) == 0) + retval = LT_ELSE; + else if (strlcmp("endif", keyword, kwlen) == 0) + retval = LT_ENDIF; + else { + linestate = LS_DIRTY; + retval = LT_PLAIN; + } + cp = skipcomment(cp); + if (*cp != '\0') { + linestate = LS_DIRTY; + if (retval == LT_TRUE || retval == LT_FALSE || + retval == LT_TRUEI || retval == LT_FALSEI) + retval = LT_IF; + if (retval == LT_ELTRUE || retval == LT_ELFALSE) + retval = LT_ELIF; + } + if (retval != LT_PLAIN && (wascomment || incomment)) { + retval += LT_DODGY; + if (incomment) + linestate = LS_DIRTY; + } + /* skipcomment should have changed the state */ + if (linestate == LS_HASH) + abort(); /* bug */ + } + if (linestate == LS_DIRTY) { + while (*cp != '\0') + cp = skipcomment(cp + 1); + } + debug("parser %s comment %s line", + comment_name[incomment], linestate_name[linestate]); + return (retval); +} + +/* + * These are the binary operators that are supported by the expression + * evaluator. Note that if support for division is added then we also + * need short-circuiting booleans because of divide-by-zero. + */ +static int op_lt(int a, int b) { return (a < b); } +static int op_gt(int a, int b) { return (a > b); } +static int op_le(int a, int b) { return (a <= b); } +static int op_ge(int a, int b) { return (a >= b); } +static int op_eq(int a, int b) { return (a == b); } +static int op_ne(int a, int b) { return (a != b); } +static int op_or(int a, int b) { return (a || b); } +static int op_and(int a, int b) { return (a && b); } + +/* + * An evaluation function takes three arguments, as follows: (1) a pointer to + * an element of the precedence table which lists the operators at the current + * level of precedence; (2) a pointer to an integer which will receive the + * value of the expression; and (3) a pointer to a char* that points to the + * expression to be evaluated and that is updated to the end of the expression + * when evaluation is complete. The function returns LT_FALSE if the value of + * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the + * expression could not be evaluated. + */ +struct ops; + +typedef Linetype eval_fn(const struct ops *, int *, const char **); + +static eval_fn eval_table, eval_unary; + +/* + * The precedence table. Expressions involving binary operators are evaluated + * in a table-driven way by eval_table. When it evaluates a subexpression it + * calls the inner function with its first argument pointing to the next + * element of the table. Innermost expressions have special non-table-driven + * handling. + */ +static const struct ops { + eval_fn *inner; + struct op { + const char *str; + int (*fn)(int, int); + } op[5]; +} eval_ops[] = { + { eval_table, { { "||", op_or } } }, + { eval_table, { { "&&", op_and } } }, + { eval_table, { { "==", op_eq }, + { "!=", op_ne } } }, + { eval_unary, { { "<=", op_le }, + { ">=", op_ge }, + { "<", op_lt }, + { ">", op_gt } } } +}; + +/* + * Function for evaluating the innermost parts of expressions, + * viz. !expr (expr) defined(symbol) symbol number + * We reset the keepthis flag when we find a non-constant subexpression. + */ +static Linetype +eval_unary(const struct ops *ops, int *valp, const char **cpp) +{ + const char *cp; + char *ep; + int sym; + + cp = skipcomment(*cpp); + if (*cp == '!') { + debug("eval%d !", ops - eval_ops); + cp++; + if (eval_unary(ops, valp, &cp) == LT_IF) + return (LT_IF); + *valp = !*valp; + } else if (*cp == '(') { + cp++; + debug("eval%d (", ops - eval_ops); + if (eval_table(eval_ops, valp, &cp) == LT_IF) + return (LT_IF); + cp = skipcomment(cp); + if (*cp++ != ')') + return (LT_IF); + } else if (isdigit((unsigned char)*cp)) { + debug("eval%d number", ops - eval_ops); + *valp = strtol(cp, &ep, 0); + cp = skipsym(cp); + } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) { + cp = skipcomment(cp+7); + debug("eval%d defined", ops - eval_ops); + if (*cp++ != '(') + return (LT_IF); + cp = skipcomment(cp); + sym = findsym(cp); + if (sym < 0) + return (LT_IF); + *valp = (value[sym] != NULL); + cp = skipsym(cp); + cp = skipcomment(cp); + if (*cp++ != ')') + return (LT_IF); + keepthis = false; + } else if (!endsym(*cp)) { + debug("eval%d symbol", ops - eval_ops); + sym = findsym(cp); + if (sym < 0) + return (LT_IF); + if (value[sym] == NULL) + *valp = 0; + else { + *valp = strtol(value[sym], &ep, 0); + if (*ep != '\0' || ep == value[sym]) + return (LT_IF); + } + cp = skipsym(cp); + keepthis = false; + } else { + debug("eval%d bad expr", ops - eval_ops); + return (LT_IF); + } + + *cpp = cp; + debug("eval%d = %d", ops - eval_ops, *valp); + return (*valp ? LT_TRUE : LT_FALSE); +} + +/* + * Table-driven evaluation of binary operators. + */ +static Linetype +eval_table(const struct ops *ops, int *valp, const char **cpp) +{ + const struct op *op; + const char *cp; + int val; + + debug("eval%d", ops - eval_ops); + cp = *cpp; + if (ops->inner(ops+1, valp, &cp) == LT_IF) + return (LT_IF); + for (;;) { + cp = skipcomment(cp); + for (op = ops->op; op->str != NULL; op++) + if (strncmp(cp, op->str, strlen(op->str)) == 0) + break; + if (op->str == NULL) + break; + cp += strlen(op->str); + debug("eval%d %s", ops - eval_ops, op->str); + if (ops->inner(ops+1, &val, &cp) == LT_IF) + return (LT_IF); + *valp = op->fn(*valp, val); + } + + *cpp = cp; + debug("eval%d = %d", ops - eval_ops, *valp); + return (*valp ? LT_TRUE : LT_FALSE); +} + +/* + * Evaluate the expression on a #if or #elif line. If we can work out + * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we + * return just a generic LT_IF. + */ +static Linetype +ifeval(const char **cpp) +{ + int ret; + int val; + + debug("eval %s", *cpp); + keepthis = killconsts ? false : true; + ret = eval_table(eval_ops, &val, cpp); + debug("eval = %d", val); + return (keepthis ? LT_IF : ret); +} + +/* + * Skip over comments, strings, and character literals and stop at the + * next character position that is not whitespace. Between calls we keep + * the comment state in the global variable incomment, and we also adjust + * the global variable linestate when we see a newline. + * XXX: doesn't cope with the buffer splitting inside a state transition. + */ +static const char * +skipcomment(const char *cp) +{ + if (text || ignoring[depth]) { + for (; isspace((unsigned char)*cp); cp++) + if (*cp == '\n') + linestate = LS_START; + return (cp); + } + while (*cp != '\0') + /* don't reset to LS_START after a line continuation */ + if (strncmp(cp, "\\\n", 2) == 0) + cp += 2; + else switch (incomment) { + case NO_COMMENT: + if (strncmp(cp, "/\\\n", 3) == 0) { + incomment = STARTING_COMMENT; + cp += 3; + } else if (strncmp(cp, "/*", 2) == 0) { + incomment = C_COMMENT; + cp += 2; + } else if (strncmp(cp, "//", 2) == 0) { + incomment = CXX_COMMENT; + cp += 2; + } else if (strncmp(cp, "\'", 1) == 0) { + incomment = CHAR_LITERAL; + linestate = LS_DIRTY; + cp += 1; + } else if (strncmp(cp, "\"", 1) == 0) { + incomment = STRING_LITERAL; + linestate = LS_DIRTY; + cp += 1; + } else if (strncmp(cp, "\n", 1) == 0) { + linestate = LS_START; + cp += 1; + } else if (strchr(" \t", *cp) != NULL) { + cp += 1; + } else + return (cp); + continue; + case CXX_COMMENT: + if (strncmp(cp, "\n", 1) == 0) { + incomment = NO_COMMENT; + linestate = LS_START; + } + cp += 1; + continue; + case CHAR_LITERAL: + case STRING_LITERAL: + if ((incomment == CHAR_LITERAL && cp[0] == '\'') || + (incomment == STRING_LITERAL && cp[0] == '\"')) { + incomment = NO_COMMENT; + cp += 1; + } else if (cp[0] == '\\') { + if (cp[1] == '\0') + cp += 1; + else + cp += 2; + } else if (strncmp(cp, "\n", 1) == 0) { + if (incomment == CHAR_LITERAL) + error("unterminated char literal"); + else + error("unterminated string literal"); + } else + cp += 1; + continue; + case C_COMMENT: + if (strncmp(cp, "*\\\n", 3) == 0) { + incomment = FINISHING_COMMENT; + cp += 3; + } else if (strncmp(cp, "*/", 2) == 0) { + incomment = NO_COMMENT; + cp += 2; + } else + cp += 1; + continue; + case STARTING_COMMENT: + if (*cp == '*') { + incomment = C_COMMENT; + cp += 1; + } else if (*cp == '/') { + incomment = CXX_COMMENT; + cp += 1; + } else { + incomment = NO_COMMENT; + linestate = LS_DIRTY; + } + continue; + case FINISHING_COMMENT: + if (*cp == '/') { + incomment = NO_COMMENT; + cp += 1; + } else + incomment = C_COMMENT; + continue; + default: + abort(); /* bug */ + } + return (cp); +} + +/* + * Skip over an identifier. + */ +static const char * +skipsym(const char *cp) +{ + while (!endsym(*cp)) + ++cp; + return (cp); +} + +/* + * Look for the symbol in the symbol table. If is is found, we return + * the symbol table index, else we return -1. + */ +static int +findsym(const char *str) +{ + const char *cp; + int symind; + + cp = skipsym(str); + if (cp == str) + return (-1); + if (symlist) { + printf("%.*s\n", (int)(cp-str), str); + /* we don't care about the value of the symbol */ + return (0); + } + for (symind = 0; symind < nsyms; ++symind) { + if (strlcmp(symname[symind], str, cp-str) == 0) { + debug("findsym %s %s", symname[symind], + value[symind] ? value[symind] : ""); + return (symind); + } + } + return (-1); +} + +/* + * Add a symbol to the symbol table. + */ +static void +addsym(bool ignorethis, bool definethis, char *sym) +{ + int symind; + char *val; + + symind = findsym(sym); + if (symind < 0) { + if (nsyms >= MAXSYMS) + errx(2, "too many symbols"); + symind = nsyms++; + } + symname[symind] = sym; + ignore[symind] = ignorethis; + val = sym + (skipsym(sym) - sym); + if (definethis) { + if (*val == '=') { + value[symind] = val+1; + *val = '\0'; + } else if (*val == '\0') + value[symind] = ""; + else + usage(); + } else { + if (*val != '\0') + usage(); + value[symind] = NULL; + } +} + +/* + * Compare s with n characters of t. + * The same as strncmp() except that it checks that s[n] == '\0'. + */ +static int +strlcmp(const char *s, const char *t, size_t n) +{ + while (n-- && *t != '\0') + if (*s != *t) + return ((unsigned char)*s - (unsigned char)*t); + else + ++s, ++t; + return ((unsigned char)*s); +} + +/* + * Diagnostics. + */ +static void +debug(const char *msg, ...) +{ + va_list ap; + + if (debugging) { + va_start(ap, msg); + vwarnx(msg, ap); + va_end(ap); + } +} + +static void +error(const char *msg) +{ + if (depth == 0) + warnx("%s: %d: %s", filename, linenum, msg); + else + warnx("%s: %d: %s (#if line %d depth %d)", + filename, linenum, msg, stifline[depth], depth); + errx(2, "output may be truncated"); +} diff --git a/include/libc-symbols.h b/include/libc-symbols.h index 6e9c5c9f0..e491aff5f 100644 --- a/include/libc-symbols.h +++ b/include/libc-symbols.h @@ -22,6 +22,16 @@ #ifndef _LIBC_SYMBOLS_H #define _LIBC_SYMBOLS_H 1 +/* This is defined for the compilation of all C library code. features.h + tests this to avoid inclusion of stubs.h while compiling the library, + before stubs.h has been generated. Some library code that is shared + with other packages also tests this symbol to see if it is being + compiled as part of the C library. We must define this before including + config.h, because it makes some definitions conditional on whether libc + itself is being compiled, or just some generator program. */ +#define _LIBC 1 + + /* This file's macros are included implicitly in the compilation of every file in the C library by -imacros. @@ -40,21 +50,11 @@ #include <bits/uClibc_arch_features.h> - -/* This is defined for the compilation of all C library code. features.h - tests this to avoid inclusion of stubs.h while compiling the library, - before stubs.h has been generated. Some library code that is shared - with other packages also tests this symbol to see if it is being - compiled as part of the C library. We must define this before including - config.h, because it makes some definitions conditional on whether libc - itself is being compiled, or just some generator program. */ -#define _LIBC 1 - /* Enable declarations of GNU extensions, since we are compiling them. */ #define _GNU_SOURCE 1 /* Prepare for the case that `__builtin_expect' is not available. */ -#if __GNUC__ == 2 && __GNUC_MINOR__ < 96 +#if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ < 96 # define __builtin_expect(x, expected_value) (x) #endif #ifndef likely @@ -72,7 +72,7 @@ #define attribute_unused __attribute__ ((unused)) -#ifdef __GNUC__ +#if defined __GNUC__ || defined __ICC # define attribute_noreturn __attribute__ ((__noreturn__)) #else # define attribute_noreturn @@ -82,12 +82,6 @@ # define IS_IN_libc 1 #endif -#ifdef __UCLIBC_NO_UNDERSCORES__ -# define NO_UNDERSCORES -#else -# undef NO_UNDERSCORES -#endif - #ifdef __UCLIBC_HAVE_ASM_SET_DIRECTIVE__ # define HAVE_ASM_SET_DIRECTIVE #else @@ -124,14 +118,16 @@ #undef C_SYMBOL_NAME #ifndef C_SYMBOL_NAME -# ifdef NO_UNDERSCORES +# ifndef __UCLIBC_UNDERSCORES__ # define C_SYMBOL_NAME(name) name # else # define C_SYMBOL_NAME(name) _##name # endif #endif -#ifndef ASM_LINE_SEP +#ifdef __UCLIBC_ASM_LINE_SEP__ +# define ASM_LINE_SEP __UCLIBC_ASM_LINE_SEP__ +#else # define ASM_LINE_SEP ; #endif @@ -174,9 +170,6 @@ # else -# define weak_function /* empty */ -# define weak_const_function /* empty */ - # define weak_alias(name, aliasname) strong_alias(name, aliasname) # define weak_extern(symbol) /* Nothing. */ @@ -246,17 +239,17 @@ .set C_SYMBOL_NAME (alias), C_SYMBOL_NAME (original) # endif # else /* ! HAVE_ASM_SET_DIRECTIVE */ -# ifdef HAVE_ASM_GLOBAL_DOT_NAME -# define weak_alias(original, alias) \ +# ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define weak_alias(original, alias) \ .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) ASM_LINE_SEP \ .weak C_SYMBOL_DOT_NAME (alias) ASM_LINE_SEP \ C_SYMBOL_DOT_NAME (alias) = C_SYMBOL_DOT_NAME (original) -# else -# define weak_alias(original, alias) \ +# else +# define weak_alias(original, alias) \ .weak C_SYMBOL_NAME (alias) ASM_LINE_SEP \ C_SYMBOL_NAME (alias) = C_SYMBOL_NAME (original) -# endif +# endif # endif # define weak_extern(symbol) \ .weak C_SYMBOL_NAME (symbol) @@ -282,25 +275,21 @@ #define __make_section_unallocated(section_string) \ __asm__ (".section " section_string "\n\t.previous"); -/* Tacking on "\n\t#" to the section name makes gcc put it's bogus +/* Tacking on "\n#APP\n\t#" to the section name makes gcc put it's bogus section attributes on what looks like a comment to the assembler. */ #ifdef __sparc__ //HAVE_SECTION_QUOTES -# define __sec_comment "\"\n\t#\"" +# define __sec_comment "\"\n#APP\n\t#\"" #else -# define __sec_comment "\n\t#" +# define __sec_comment "\n#APP\n\t#" #endif /* When a reference to SYMBOL is encountered, the linker will emit a warning message MSG. */ -#if defined(__cris__) || defined(__vax__) -# define link_warning(symbol, msg) -#else -# define link_warning(symbol, msg) \ +#define link_warning(symbol, msg) \ __make_section_unallocated (".gnu.warning." #symbol) \ static const char __evoke_link_warning_##symbol[] \ __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \ = msg; -#endif /* Handling on non-exported internal names. We have to do this only for shared code. */ @@ -414,8 +403,9 @@ * d. hidden_def() in asm is _hidden_strong_alias (not strong_alias) */ /* Arrange to hide uClibc internals */ -#if defined __GNUC__ && defined __GNUC_MINOR__ && \ - ( __GNUC__ >= 3 && __GNUC_MINOR__ >= 3 ) || __GNUC__ >= 4 +#if (defined __GNUC__ && \ + (defined __GNUC_MINOR__ && ( __GNUC__ >= 3 && __GNUC_MINOR__ >= 3 ) \ + || __GNUC__ >= 4)) || defined __ICC # define attribute_hidden __attribute__ ((visibility ("hidden"))) # define __hidden_proto_hiddenattr(attrs...) __attribute__ ((visibility ("hidden"), ##attrs)) #else @@ -423,7 +413,7 @@ # define __hidden_proto_hiddenattr(attrs...) #endif -#if !defined STATIC && !defined __BCC__ +#if /*!defined STATIC &&*/ !defined __BCC__ # ifndef __ASSEMBLER__ # define hidden_proto(name, attrs...) __hidden_proto (name, __GI_##name, ##attrs) # define __hidden_proto(name, internal, attrs...) \ @@ -435,9 +425,12 @@ # define __hidden_ver1(local, internal, name) \ extern __typeof (name) __EI_##name __asm__(__hidden_asmname (#internal)); \ extern __typeof (name) __EI_##name __attribute__((alias (__hidden_asmname1 (,#local)))) +# define hidden_ver(local, name) __hidden_ver1(local, __GI_##name, name); +# define hidden_data_ver(local, name) hidden_ver(local, name) # define hidden_def(name) __hidden_ver1(__GI_##name, name, name); # define hidden_data_def(name) hidden_def(name) -# define hidden_weak(name) __hidden_ver1(__GI_##name, name, name) __attribute__((weak)); +# define hidden_weak(name) \ + __hidden_ver1(__GI_##name, name, name) __attribute__((weak)); # define hidden_data_weak(name) hidden_weak(name) # else /* __ASSEMBLER__ */ @@ -494,26 +487,36 @@ hidden_proto doesn't make sense for assembly but the equivalent is to call via the HIDDEN_JUMPTARGET macro instead of JUMPTARGET. */ # define hidden_def(name) _hidden_strong_alias (name, __GI_##name) -# define hidden_data_def(name) _hidden_strong_alias (name, __GI_##name) # define hidden_weak(name) _hidden_weak_alias (name, __GI_##name) +# define hidden_ver(local, name) strong_alias (local, __GI_##name) +# define hidden_data_def(name) _hidden_strong_alias (name, __GI_##name) # define hidden_data_weak(name) _hidden_weak_alias (name, __GI_##name) -# define HIDDEN_JUMPTARGET(name) __GI_##name +# define hidden_data_ver(local, name) strong_data_alias (local, __GI_##name) +# ifdef HAVE_ASM_GLOBAL_DOT_NAME +# define HIDDEN_JUMPTARGET(name) .__GI_##name +# else +# define HIDDEN_JUMPTARGET(name) __GI_##name +# endif # endif /* __ASSEMBLER__ */ #else /* SHARED */ # ifndef __ASSEMBLER__ # define hidden_proto(name, attrs...) # else # define HIDDEN_JUMPTARGET(name) name -# endif -# define hidden_def(name) -# define hidden_data_def(name) +# endif /* Not __ASSEMBLER__ */ # define hidden_weak(name) +# define hidden_def(name) +# define hidden_ver(local, name) # define hidden_data_weak(name) +# define hidden_data_def(name) +# define hidden_data_ver(local, name) #endif /* SHARED */ /* uClibc does not support versioning yet. */ #define versioned_symbol(lib, local, symbol, version) /* weak_alias(local, symbol) */ +#undef hidden_ver #define hidden_ver(local, name) /* strong_alias(local, __GI_##name) */ +#undef hidden_data_ver #define hidden_data_ver(local, name) /* strong_alias(local,__GI_##name) */ #if !defined NOT_IN_libc diff --git a/include/string.h b/include/string.h index 87d953449..35807d6a7 100644 --- a/include/string.h +++ b/include/string.h @@ -38,10 +38,12 @@ __BEGIN_NAMESPACE_STD extern void *memcpy (void *__restrict __dest, __const void *__restrict __src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(memcpy) /* Copy N bytes of SRC to DEST, guaranteeing correct behavior for overlapping strings. */ extern void *memmove (void *__dest, __const void *__src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(memmove) __END_NAMESPACE_STD /* Copy no more than N bytes of SRC to DEST, stopping when C is found. @@ -51,20 +53,24 @@ __END_NAMESPACE_STD extern void *memccpy (void *__restrict __dest, __const void *__restrict __src, int __c, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(memccpy) #endif /* SVID. */ __BEGIN_NAMESPACE_STD /* Set N bytes of S to C. */ extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1)); +libc_hidden_proto(memset) /* Compare N bytes of S1 and S2. */ extern int memcmp (__const void *__s1, __const void *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(memcmp) /* Search N bytes of S for C. */ extern void *memchr (__const void *__s, int __c, size_t __n) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(memchr) __END_NAMESPACE_STD #ifdef __USE_GNU @@ -72,10 +78,12 @@ __END_NAMESPACE_STD length limit. */ extern void *rawmemchr (__const void *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(rawmemchr) /* Search N bytes of S for the final occurrence of C. */ extern void *memrchr (__const void *__s, int __c, size_t __n) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(memrchr) #endif @@ -83,32 +91,40 @@ __BEGIN_NAMESPACE_STD /* Copy SRC to DEST. */ extern char *strcpy (char *__restrict __dest, __const char *__restrict __src) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strcpy) /* Copy no more than N characters of SRC to DEST. */ extern char *strncpy (char *__restrict __dest, __const char *__restrict __src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strncpy) /* Append SRC onto DEST. */ extern char *strcat (char *__restrict __dest, __const char *__restrict __src) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strcat) /* Append no more than N characters from SRC onto DEST. */ extern char *strncat (char *__restrict __dest, __const char *__restrict __src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strncat) /* Compare S1 and S2. */ extern int strcmp (__const char *__s1, __const char *__s2) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strcmp) /* Compare N characters of S1 and S2. */ extern int strncmp (__const char *__s1, __const char *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strncmp) /* Compare the collated forms of S1 and S2. */ extern int strcoll (__const char *__s1, __const char *__s2) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strcoll) /* Put a transformation of SRC into no more than N bytes of DEST. */ extern size_t strxfrm (char *__restrict __dest, __const char *__restrict __src, size_t __n) __THROW __nonnull ((2)); +libc_hidden_proto(strxfrm) __END_NAMESPACE_STD #if defined __USE_GNU && defined __UCLIBC_HAS_XLOCALE__ @@ -120,15 +136,18 @@ __END_NAMESPACE_STD /* Compare the collated forms of S1 and S2 using rules from L. */ extern int strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l) __THROW __attribute_pure__ __nonnull ((1, 2, 3)); +libc_hidden_proto(strcoll_l) /* Put a transformation of SRC into no more than N bytes of DEST. */ extern size_t strxfrm_l (char *__dest, __const char *__src, size_t __n, __locale_t __l) __THROW __nonnull ((2, 4)); +libc_hidden_proto(strxfrm_l) #endif #if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED /* Duplicate S, returning an identical malloc'd string. */ extern char *strdup (__const char *__s) __THROW __attribute_malloc__ __nonnull ((1)); +libc_hidden_proto(strdup) #endif /* Return a malloc'd copy of at most N bytes of STRING. The @@ -137,6 +156,7 @@ extern char *strdup (__const char *__s) #if defined __USE_GNU extern char *strndup (__const char *__string, size_t __n) __THROW __attribute_malloc__ __nonnull ((1)); +libc_hidden_proto(strndup) #endif #if defined __USE_GNU && defined __GNUC__ @@ -166,9 +186,11 @@ __BEGIN_NAMESPACE_STD /* Find the first occurrence of C in S. */ extern char *strchr (__const char *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(strchr) /* Find the last occurrence of C in S. */ extern char *strrchr (__const char *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(strrchr) __END_NAMESPACE_STD #ifdef __USE_GNU @@ -176,6 +198,7 @@ __END_NAMESPACE_STD the closing NUL byte in case C is not found in S. */ extern char *strchrnul (__const char *__s, int __c) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(strchrnul) #endif __BEGIN_NAMESPACE_STD @@ -183,21 +206,26 @@ __BEGIN_NAMESPACE_STD consists entirely of characters not in REJECT. */ extern size_t strcspn (__const char *__s, __const char *__reject) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strcspn) /* Return the length of the initial segment of S which consists entirely of characters in ACCEPT. */ extern size_t strspn (__const char *__s, __const char *__accept) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strspn) /* Find the first occurrence in S of any character in ACCEPT. */ extern char *strpbrk (__const char *__s, __const char *__accept) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strpbrk) /* Find the first occurrence of NEEDLE in HAYSTACK. */ extern char *strstr (__const char *__haystack, __const char *__needle) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strstr) /* Divide S into tokens separated by characters in DELIM. */ extern char *strtok (char *__restrict __s, __const char *__restrict __delim) __THROW __nonnull ((2)); +libc_hidden_proto(strtok) __END_NAMESPACE_STD /* Divide S into tokens separated by characters in DELIM. Information @@ -212,12 +240,14 @@ extern char *__strtok_r (char *__restrict __s, extern char *strtok_r (char *__restrict __s, __const char *__restrict __delim, char **__restrict __save_ptr) __THROW __nonnull ((2, 3)); +libc_hidden_proto(strtok_r) #endif #ifdef __USE_GNU /* Similar to `strstr' but this function ignores the case of both strings. */ extern char *strcasestr (__const char *__haystack, __const char *__needle) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strcasestr) #endif #ifdef __USE_GNU @@ -227,6 +257,7 @@ extern char *strcasestr (__const char *__haystack, __const char *__needle) extern void *memmem (__const void *__haystack, size_t __haystacklen, __const void *__needle, size_t __needlelen) __THROW __attribute_pure__ __nonnull ((1, 3)); +libc_hidden_proto(memmem) /* Copy N bytes of SRC to DEST, return pointer to bytes after the last written byte. */ @@ -238,6 +269,7 @@ extern void *__mempcpy (void *__restrict __dest, extern void *mempcpy (void *__restrict __dest, __const void *__restrict __src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(mempcpy) #endif @@ -245,6 +277,7 @@ __BEGIN_NAMESPACE_STD /* Return the length of S. */ extern size_t strlen (__const char *__s) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(strlen) __END_NAMESPACE_STD #ifdef __USE_GNU @@ -252,12 +285,14 @@ __END_NAMESPACE_STD If no '\0' terminator is found in that many characters, return MAXLEN. */ extern size_t strnlen (__const char *__string, size_t __maxlen) __THROW __attribute_pure__ __nonnull ((1)); +libc_hidden_proto(strnlen) #endif __BEGIN_NAMESPACE_STD /* Return a string describing the meaning of the `errno' code in ERRNUM. */ extern char *strerror (int __errnum) __THROW; +libc_hidden_proto(strerror) __END_NAMESPACE_STD #if defined __USE_XOPEN2K || defined __USE_MISC /* Reentrant version of `strerror'. @@ -337,6 +372,7 @@ extern char *rindex (__const char *__s, int __c) /* Return the position of the first bit set in I, or 0 if none are set. The least-significant bit is position 1, the most-significant 32. */ extern int ffs (int __i) __THROW __attribute__ ((__const__)); +libc_hidden_proto(ffs) /* The following two functions are non-standard but necessary for non-32 bit platforms. */ @@ -351,10 +387,12 @@ __extension__ extern int ffsll (long long int __ll) /* Compare S1 and S2, ignoring case. */ extern int strcasecmp (__const char *__s1, __const char *__s2) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strcasecmp) /* Compare no more than N chars of S1 and S2, ignoring case. */ extern int strncasecmp (__const char *__s1, __const char *__s2, size_t __n) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strncasecmp) #endif /* Use BSD. */ #if defined __USE_GNU && defined __UCLIBC_HAS_XLOCALE__ @@ -363,10 +401,12 @@ extern int strncasecmp (__const char *__s1, __const char *__s2, size_t __n) extern int strcasecmp_l (__const char *__s1, __const char *__s2, __locale_t __loc) __THROW __attribute_pure__ __nonnull ((1, 2, 3)); +libc_hidden_proto(strcasecmp_l) extern int strncasecmp_l (__const char *__s1, __const char *__s2, size_t __n, __locale_t __loc) __THROW __attribute_pure__ __nonnull ((1, 2, 4)); +libc_hidden_proto(strncasecmp_l) #endif #ifdef __USE_BSD @@ -375,6 +415,7 @@ extern int strncasecmp_l (__const char *__s1, __const char *__s2, extern char *strsep (char **__restrict __stringp, __const char *__restrict __delim) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strsep) #endif #ifdef __USE_GNU @@ -382,10 +423,12 @@ extern char *strsep (char **__restrict __stringp, #if 0 extern int strverscmp (__const char *__s1, __const char *__s2) __THROW __attribute_pure__ __nonnull ((1, 2)); +libc_hidden_proto(strverscmp) #endif /* Return a string describing the meaning of the signal number in SIG. */ extern char *strsignal (int __sig) __THROW; +libc_hidden_proto(strsignal) /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ #if 0 /* uClibc: disabled */ @@ -394,6 +437,7 @@ extern char *__stpcpy (char *__restrict __dest, __const char *__restrict __src) #endif extern char *stpcpy (char *__restrict __dest, __const char *__restrict __src) __THROW __nonnull ((1, 2)); +libc_hidden_proto(stpcpy) /* Copy no more than N characters of SRC to DEST, returning the address of the last character written into DEST. */ @@ -405,6 +449,7 @@ extern char *__stpncpy (char *__restrict __dest, extern char *stpncpy (char *__restrict __dest, __const char *__restrict __src, size_t __n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(stpncpy) #if 0 /* uClibc does not support strfry or memfrob. */ /* Sautee STRING briskly. */ @@ -420,6 +465,7 @@ extern void *memfrob (void *__s, size_t __n) __THROW __nonnull ((1)); in <libgen.h>) which makes the XPG version of this function available. */ extern char *basename (__const char *__filename) __THROW __nonnull ((1)); +libc_hidden_proto(basename) # endif #endif @@ -428,10 +474,127 @@ extern char *basename (__const char *__filename) __THROW __nonnull ((1)); /* Two OpenBSD extension functions. */ extern size_t strlcat(char *__restrict dst, const char *__restrict src, size_t n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strlcat) extern size_t strlcpy(char *__restrict dst, const char *__restrict src, size_t n) __THROW __nonnull ((1, 2)); +libc_hidden_proto(strlcpy) #endif __END_DECLS +#ifdef UCLIBC_INTERNAL +/* In the same order and with the same defines */ +libc_hidden_proto(memcpy) +libc_hidden_proto(memmove) +#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN +libc_hidden_proto(memccpy) +#endif /* SVID. */ +libc_hidden_proto(memset) +libc_hidden_proto(memcmp) +libc_hidden_proto(memchr) +#ifdef __USE_GNU +libc_hidden_proto(rawmemchr) +libc_hidden_proto(memrchr) +#endif +libc_hidden_proto(strcpy) +libc_hidden_proto(strncpy) +libc_hidden_proto(strcat) +libc_hidden_proto(strncat) +libc_hidden_proto(strcmp) +libc_hidden_proto(strncmp) +libc_hidden_proto(strcoll) +libc_hidden_proto(strxfrm) +#if defined __USE_GNU && defined __UCLIBC_HAS_XLOCALE__ +libc_hidden_proto(strcoll_l) +libc_hidden_proto(strxfrm_l) +#endif +#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED +libc_hidden_proto(strdup) +#endif +#if defined __USE_GNU +libc_hidden_proto(strndup) +#endif +libc_hidden_proto(strchr) +libc_hidden_proto(strrchr) +#ifdef __USE_GNU +libc_hidden_proto(strchrnul) +#endif +libc_hidden_proto(strcspn) +libc_hidden_proto(strspn) +libc_hidden_proto(strpbrk) +libc_hidden_proto(strstr) +libc_hidden_proto(strtok) +#if 0 /* uClibc: disabled */ +libc_hidden_proto(__strtok_r) +#endif +#if defined __USE_POSIX || defined __USE_MISC +libc_hidden_proto(strtok_r) +#endif +#ifdef __USE_GNU +libc_hidden_proto(strcasestr) +#endif +#ifdef __USE_GNU +libc_hidden_proto(memmem) +#if 0 /* uClibc: disabled */ +libc_hidden_proto(__mempcpy) +#endif +libc_hidden_proto(mempcpy) +#endif +libc_hidden_proto(strlen) +#ifdef __USE_GNU +libc_hidden_proto(strnlen) +#endif +libc_hidden_proto(strerror) +/* TODO: insert strerror_r mess here */ +#if 0 /* uClibc: disabled */ +libc_hidden_proto(__bzero) +#endif +#ifdef __USE_BSD +/* No libc_hidden_proto for bcopy etc., since uClibc doesn't itself use the + legacy functions. */ +libc_hidden_proto(ffs) +#if 0 /*def __USE_GNU*/ +libc_hidden_proto(ffsl) +# ifdef __GNUC__ +libc_hidden_proto(ffsll) +# endif +# endif +libc_hidden_proto(strcasecmp) +libc_hidden_proto(strncasecmp) +#endif /* Use BSD. */ +#if defined __USE_GNU && defined __UCLIBC_HAS_XLOCALE__ +libc_hidden_proto(strcasecmp_l) +libc_hidden_proto(strncasecmp_l) +#endif +#ifdef __USE_BSD +libc_hidden_proto(strsep) +#endif +#ifdef __USE_GNU +#if 0 +libc_hidden_proto(strverscmp) +#endif +libc_hidden_proto(strsignal) +#if 0 /* uClibc: disabled */ +libc_hidden_proto(__stpcpy) +#endif +libc_hidden_proto(stpcpy) +#if 0 /* uClibc: disabled */ +libc_hidden_proto(__stpncpy) +#endif +libc_hidden_proto(stpncpy) +#if 0 /* uClibc does not support strfry or memfrob. */ +libc_hidden_proto(strfry) +libc_hidden_proto(memfrob) +#endif +# ifndef basename +libc_hidden_proto(basename) +# endif +#endif +#ifdef __USE_BSD +libc_hidden_proto(strlcat) +libc_hidden_proto(strlcpy) +#endif +#endif + + #endif /* string.h */ diff --git a/include/strings.h b/include/strings.h index 107c53a4f..31e620673 100644 --- a/include/strings.h +++ b/include/strings.h @@ -90,6 +90,10 @@ extern int strncasecmp (__const char *__s1, __const char *__s2, size_t __n) __END_DECLS +#ifdef UCLIBC_INTERNAL +#error "<strings.h> should not be included from libc." +#endif + #endif /* string.h */ #endif /* strings.h */ diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index 950183e46..6ebb4a3b4 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -55,7 +55,7 @@ unsigned long __dl_runtime_resolve(unsigned long sym_index, symname = strtab + sym->st_name; new_addr = (unsigned long) _dl_find_hash(symname, - tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); if (unlikely(!new_addr)) { _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname); @@ -144,8 +144,8 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt, struct elf_resolve *tpnt_tls = tpnt; if (ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_LOCAL) { - _dl_find_hash2((strtab + symtab[symtab_index].st_name), - _dl_symbol_tables, NULL, 1, &sym_tls, &tpnt_tls); + _dl_find_hash((strtab + symtab[symtab_index].st_name), + _dl_symbol_tables, NULL, 1, &sym_tls); } switch (reloc_type) @@ -259,12 +259,12 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy) } else { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); } } else if (sym->st_shndx == SHN_COMMON) { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); } else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC && *got_entry != sym->st_value && tmp_lazy) { @@ -276,7 +276,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy) } else { *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT); + sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); } got_entry++; diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index b09684ce4..6d6d18a96 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -136,7 +136,6 @@ #define __FORCE_GLIBC #include <features.h> #include <string.h> -#include <strings.h> #include <stdio.h> #include <signal.h> #include <errno.h> diff --git a/libc/inet/rpc/ruserpass.c b/libc/inet/rpc/ruserpass.c index 0adcbf1d3..97f1284b3 100644 --- a/libc/inet/rpc/ruserpass.c +++ b/libc/inet/rpc/ruserpass.c @@ -40,7 +40,6 @@ #include <stdio_ext.h> #include <stdlib.h> #include <string.h> -#include <strings.h> #include <unistd.h> libc_hidden_proto(strcat) diff --git a/libc/misc/internals/tempname.c b/libc/misc/internals/tempname.c index dc125020b..0883259bd 100644 --- a/libc/misc/internals/tempname.c +++ b/libc/misc/internals/tempname.c @@ -45,8 +45,8 @@ #include <sys/time.h> #include "tempname.h" -libc_hidden_proto(strlen) -libc_hidden_proto(strcmp) +/* Experimentally off - libc_hidden_proto(strlen) */ +/* Experimentally off - libc_hidden_proto(strcmp) */ libc_hidden_proto(sprintf) libc_hidden_proto(mkdir) libc_hidden_proto(open) diff --git a/libc/misc/regex/regex.c b/libc/misc/regex/regex.c index 192034b4e..f39492bdf 100644 --- a/libc/misc/regex/regex.c +++ b/libc/misc/regex/regex.c @@ -36,7 +36,6 @@ #include <stdbool.h> #include <stdint.h> #include <string.h> -#include <strings.h> #include <stdlib.h> #ifdef __UCLIBC_HAS_WCHAR__ #define RE_ENABLE_I18N diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c index 93afa9b68..b5278bce1 100644 --- a/libc/misc/time/time.c +++ b/libc/misc/time/time.c @@ -133,7 +133,6 @@ #include <stdlib.h> #include <stddef.h> #include <string.h> -#include <strings.h> #include <time.h> #include <sys/time.h> #include <limits.h> diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c index 32ad41ee6..64bab37e0 100644 --- a/libc/misc/wchar/wchar.c +++ b/libc/misc/wchar/wchar.c @@ -1191,7 +1191,6 @@ typedef struct { #include <iconv.h> #include <string.h> -#include <strings.h> #include <endian.h> #include <byteswap.h> diff --git a/libc/stdlib/realpath.c b/libc/stdlib/realpath.c index aae8580a5..b28d6f07e 100644 --- a/libc/stdlib/realpath.c +++ b/libc/stdlib/realpath.c @@ -14,7 +14,6 @@ #include <unistd.h> #include <stdio.h> #include <string.h> -#include <strings.h> #include <limits.h> /* for PATH_MAX */ #include <sys/param.h> /* for MAXPATHLEN */ #include <errno.h> diff --git a/libc/sysdeps/linux/common/gethstnm.c b/libc/sysdeps/linux/common/gethstnm.c deleted file mode 100644 index fc5a72c8d..000000000 --- a/libc/sysdeps/linux/common/gethstnm.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> - * - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -#include <string.h> -#include <unistd.h> -#include <sys/utsname.h> -#include <errno.h> - -libc_hidden_proto(gethostname) - -libc_hidden_proto(strlen) -libc_hidden_proto(strcpy) -libc_hidden_proto(uname) - -int -gethostname(char *name, size_t len) -{ - struct utsname uts; - - if (name == NULL) { - __set_errno(EINVAL); - return -1; - } - - if (uname(&uts) == -1) return -1; - - if (strlen(uts.nodename)+1 > len) { - __set_errno(EINVAL); - return -1; - } - strcpy(name, uts.nodename); - return 0; -} -libc_hidden_def(gethostname) diff --git a/libc/sysdeps/linux/mips/__syscall_error.c b/libc/sysdeps/linux/mips/__syscall_error.c new file mode 100644 index 000000000..5e109a83b --- /dev/null +++ b/libc/sysdeps/linux/mips/__syscall_error.c @@ -0,0 +1,18 @@ +/* Wrapper for setting errno. + * + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <errno.h> +#include <features.h> + +/* This routine is jumped to by all the syscall handlers, to stash + * an error number into errno. */ +int __syscall_error(int err_no) attribute_hidden; +int __syscall_error(int err_no) +{ + __set_errno(err_no); + return -1; +} diff --git a/libc/sysdeps/linux/mips/clone.S b/libc/sysdeps/linux/mips/clone.S index 716cd993f..03162db43 100644 --- a/libc/sysdeps/linux/mips/clone.S +++ b/libc/sysdeps/linux/mips/clone.S @@ -125,3 +125,4 @@ __thread_start: move a0,v0 jal HIDDEN_JUMPTARGET(_exit) .end __thread_start +weak_alias(clone, __clone) diff --git a/libc/sysdeps/linux/mips/sys/asm.h b/libc/sysdeps/linux/mips/sys/asm.h index 76f6af3e1..4c8bd9cb2 100644 --- a/libc/sysdeps/linux/mips/sys/asm.h +++ b/libc/sysdeps/linux/mips/sys/asm.h @@ -469,5 +469,20 @@ symbol = value # define MFC0 dmfc0 # define MTC0 dmtc0 #endif +/* The MIPS archtectures do not have a uniform memory model. Particular + platforms may provide additional guarantees - for instance, the R4000 + LL and SC instructions implicitly perform a SYNC, and the 4K promises + strong ordering. + + However, in the absence of those guarantees, we must assume weak ordering + and SYNC explicitly where necessary. + + Some obsolete MIPS processors may not support the SYNC instruction. This + applies to "true" MIPS I processors; most of the processors which compile + using MIPS I implement parts of MIPS II. */ + +#ifndef MIPS_SYNC +# define MIPS_SYNC sync +#endif #endif /* sys/asm.h */ diff --git a/libpthread/nptl/sysdeps/pthread/sigaction.c b/libpthread/nptl/sysdeps/pthread/sigaction.c index 54b5d2de4..0877e534f 100644 --- a/libpthread/nptl/sysdeps/pthread/sigaction.c +++ b/libpthread/nptl/sysdeps/pthread/sigaction.c @@ -20,21 +20,20 @@ /* This is tricky. GCC doesn't like #include_next in the primary source file and even if it did, the first #include_next is this exact file anyway. */ -#ifndef LIBC_SIGACTION - #include <pthreadP.h> +#include <features.h> +#include <errno.h> +#include <signal.h> +extern __typeof(sigaction) __libc_sigaction; +extern __typeof(sigaction) __sigaction; /* We use the libc implementation but we tell it to not allow SIGCANCEL or SIGTIMER to be handled. */ -# define LIBC_SIGACTION 1 - -# include <sigaction.c> - int -sigaction (int sig, const struct sigaction *act, struct sigaction *oact); - -int -__sigaction (int sig, const struct sigaction *act, struct sigaction *oact) +__sigaction (sig, act, oact) + int sig; + const struct sigaction *act; + struct sigaction *oact; { if (__builtin_expect (sig == SIGCANCEL || sig == SIGSETXID, 0)) { @@ -47,8 +46,3 @@ __sigaction (int sig, const struct sigaction *act, struct sigaction *oact) libc_hidden_proto(sigaction) weak_alias (__sigaction, sigaction) libc_hidden_weak(sigaction) -#else - -# include_next <sigaction.c> - -#endif /* LIBC_SIGACTION */ diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch index 8011cc087..b5a21342b 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/Makefile.arch @@ -5,7 +5,7 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -libpthread_SSRC = pt-clone.S pt-vfork.S +libpthread_SSRC = pt-vfork.S libpthread_CSRC = pthread_once.c libc_a_CSRC = fork.c diff --git a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h index b8c5280ab..01c1a2891 100644 --- a/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h +++ b/libpthread/nptl/sysdeps/unix/sysv/linux/mips/sysdep.h @@ -75,7 +75,7 @@ #undef INTERNAL_SYSCALL_NCS #define INTERNAL_SYSCALL_NCS(number, err, nr, args...) \ internal_syscall##nr (= number, , "r" (__v0), err, args) - +#undef internal_syscall0 #define internal_syscall0(ncs_init, cs_init, input, err, dummy...) \ ({ \ long _sys_result; \ @@ -97,6 +97,7 @@ _sys_result; \ }) +#undef internal_syscall1 #define internal_syscall1(ncs_init, cs_init, input, err, arg1) \ ({ \ long _sys_result; \ @@ -119,6 +120,7 @@ _sys_result; \ }) +#undef internal_syscall2 #define internal_syscall2(ncs_init, cs_init, input, err, arg1, arg2) \ ({ \ long _sys_result; \ @@ -142,6 +144,7 @@ _sys_result; \ }) +#undef internal_syscall3 #define internal_syscall3(ncs_init, cs_init, input, err, arg1, arg2, arg3)\ ({ \ long _sys_result; \ @@ -166,6 +169,7 @@ _sys_result; \ }) +#undef internal_syscall4 #define internal_syscall4(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4)\ ({ \ long _sys_result; \ @@ -196,6 +200,7 @@ of GCC 3.4.3, this is sufficient. */ #define FORCE_FRAME_POINTER alloca (4) +#undef internal_syscall5 #define internal_syscall5(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5)\ ({ \ long _sys_result; \ @@ -225,6 +230,7 @@ _sys_result; \ }) +#undef internal_syscall6 #define internal_syscall6(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6)\ ({ \ long _sys_result; \ @@ -255,6 +261,7 @@ _sys_result; \ }) +#undef internal_syscall7 #define internal_syscall7(ncs_init, cs_init, input, err, arg1, arg2, arg3, arg4, arg5, arg6, arg7)\ ({ \ long _sys_result; \ |