1#!/bin/sh 2 3# Usage: make-syscalls.sh ../sysdeps/unix/common 4# Expects $sysdirs in environment. 5 6############################################################################## 7# 8# This script is used to process the syscall data encoded in the various 9# syscalls.list files to produce thin assembly syscall wrappers around the 10# appropriate OS syscall. See syscall-template.S for more details on the 11# actual wrapper. 12# 13# Syscall Signature Prefixes: 14# 15# E: errno and return value are not set by the call 16# V: errno is not set, but errno or zero (success) is returned from the call 17# 18# Syscall Signature Key Letters: 19# 20# a: unchecked address (e.g., 1st arg to mmap) 21# b: non-NULL buffer (e.g., 2nd arg to read; return value from mmap) 22# B: optionally-NULL buffer (e.g., 4th arg to getsockopt) 23# f: buffer of 2 ints (e.g., 4th arg to socketpair) 24# F: 3rd arg to fcntl 25# i: scalar (any signedness & size: int, long, long long, enum, whatever) 26# I: 3rd arg to ioctl 27# n: scalar buffer length (e.g., 3rd arg to read) 28# N: pointer to value/return scalar buffer length (e.g., 6th arg to recvfrom) 29# p: non-NULL pointer to typed object (e.g., any non-void* arg) 30# P: optionally-NULL pointer to typed object (e.g., 3rd argument to sigaction) 31# s: non-NULL string (e.g., 1st arg to open) 32# S: optionally-NULL string (e.g., 1st arg to acct) 33# U: unsigned long int (32-bit types are zero-extended to 64-bit types) 34# v: vararg scalar (e.g., optional 3rd arg to open) 35# V: byte-per-page vector (3rd arg to mincore) 36# W: wait status, optionally-NULL pointer to int (e.g., 2nd arg of wait4) 37# 38 39############################################################################## 40 41thisdir=$1; shift 42 43echo '' 44echo \#### DIRECTORY = $thisdir 45# Check each sysdep dir with higher priority than this one, 46# and remove from $calls all the functions found in other dirs. 47# Punt when we reach the directory defining these syscalls. 48sysdirs=`for dir in $sysdirs; do 49 test $dir = $thisdir && break; echo $dir; done` 50echo \#### SYSDIRS = $sysdirs 51 52# Get the list of system calls for this directory. 53calls=`sed 's/#.*$// 54/^[ ]*$/d' $thisdir/syscalls.list` 55 56calls=`echo "$calls" | 57while read file caller rest; do 58 # Remove each syscall that is implemented by a file in $dir. 59 # If a syscall specified a "caller", then only compile that syscall 60 # if the caller function is also implemented in this directory. 61 srcfile=-; 62 for dir in $sysdirs; do 63 { test -f $dir/$file.c && srcfile=$dir/$file.c; } || 64 { test -f $dir/$file.S && srcfile=$dir/$file.S; } || 65 { test x$caller != x- && 66 { { test -f $dir/$caller.c && srcfile=$dir/$caller.c; } || 67 { test -f $dir/$caller.S && srcfile=$dir/$caller.S; }; }; } && break; 68 done; 69 echo $file $srcfile $caller $rest; 70done` 71 72# Any calls left? 73test -n "$calls" || exit 0 74 75# This uses variables $weak, $strong, and $any_versioned. 76emit_weak_aliases() 77{ 78 # A shortcoming in the current gas is that it will only allow one 79 # version-alias per symbol. So we create new strong aliases as needed. 80 vcount="" 81 82 # We use the <shlib-compat.h> macros to generate the versioned aliases 83 # so that the version sets can be mapped to the configuration's 84 # minimum version set as per shlib-versions DEFAULT lines. If an 85 # entry point is specified in the form NAME@VERSION:OBSOLETED, a 86 # SHLIB_COMPAT conditional is generated. 87 if [ $any_versioned = t ]; then 88 echo " echo '#include <shlib-compat.h>'; \\" 89 fi 90 91 for name in $weak; do 92 case $name in 93 *@@*) 94 base=`echo $name | sed 's/@@.*//'` 95 ver=`echo $name | sed 's/.*@@//;s/\./_/g'` 96 echo " echo '#if IS_IN (libc)'; \\" 97 if test -z "$vcount" ; then 98 source=$strong 99 vcount=1 100 else 101 source="${strong}_${vcount}" 102 vcount=`expr $vcount + 1` 103 echo " echo 'strong_alias ($strong, $source)'; \\" 104 fi 105 echo " echo 'versioned_symbol (libc, $source, $base, $ver)'; \\" 106 echo " echo '#else'; \\" 107 echo " echo 'weak_alias ($strong, $base)'; \\" 108 echo " echo '#endif'; \\" 109 ;; 110 *@*) 111 base=`echo $name | sed 's/@.*//'` 112 ver=`echo $name | sed 's/.*@//;s/\./_/g'` 113 case $ver in 114 *:*) 115 compat_ver=${ver#*:} 116 ver=${ver%%:*} 117 compat_cond=" && SHLIB_COMPAT (libc, $ver, $compat_ver)" 118 ;; 119 *) 120 compat_cond= 121 ;; 122 esac 123 echo " echo '#if defined SHARED && IS_IN (libc)$compat_cond'; \\" 124 if test -z "$vcount" ; then 125 source=$strong 126 vcount=1 127 else 128 source="${strong}_${vcount}" 129 vcount=`expr $vcount + 1` 130 echo " echo 'strong_alias ($strong, $source)'; \\" 131 fi 132 echo " echo 'compat_symbol (libc, $source, $base, $ver)'; \\" 133 echo " echo '#endif'; \\" 134 ;; 135 !*) 136 name=`echo $name | sed 's/.//'` 137 echo " echo 'strong_alias ($strong, $name)'; \\" 138 echo " echo 'hidden_def ($name)'; \\" 139 ;; 140 *) 141 echo " echo 'weak_alias ($strong, $name)'; \\" 142 echo " echo 'hidden_weak ($name)'; \\" 143 ;; 144 esac 145 done 146} 147 148 149# Emit rules to compile the syscalls remaining in $calls. 150echo "$calls" | 151while read file srcfile caller syscall args strong weak; do 152 153 case x"$syscall" in 154 x-) callnum=_ ;; 155 *) 156 # Figure out if $syscall is defined with a number in syscall.h. 157 callnum=- 158 eval `{ echo "#include <sysdep.h>"; 159 echo "callnum=SYS_ify ($syscall)"; } | 160 $asm_CPP -D__OPTIMIZE__ - | 161 sed -n -e "/^callnum=.*$syscall/d" \ 162 -e "/^\(callnum=\)[ ]*\(.*\)/s//\1'\2'/p"` 163 ;; 164 esac 165 166 noerrno=0 167 errval=0 168 case $args in 169 E*) noerrno=1; args=`echo $args | sed 's/E:\?//'`;; 170 V*) errval=1; args=`echo $args | sed 's/V:\?//'`;; 171 esac 172 173 # Derive the number of arguments from the argument signature 174 case $args in 175 [0-9]) nargs=$args;; 176 ?:) nargs=0;; 177 ?:?) nargs=1;; 178 ?:??) nargs=2;; 179 ?:???) nargs=3;; 180 ?:????) nargs=4;; 181 ?:?????) nargs=5;; 182 ?:??????) nargs=6;; 183 ?:???????) nargs=7;; 184 ?:????????) nargs=8;; 185 ?:?????????) nargs=9;; 186 esac 187 188 # Derive the unsigned long int arguments from the argument signature 189 ulong_arg_1=0 190 ulong_arg_2=0 191 ulong_count=0 192 for U in $(echo $args | sed -e "s/.*:/:/" | grep -ob U) 193 do 194 ulong_count=$(expr $ulong_count + 1) 195 ulong_arg=$(echo $U | sed -e "s/:U//") 196 case $ulong_count in 197 1) 198 ulong_arg_1=$ulong_arg 199 ;; 200 2) 201 ulong_arg_2=$ulong_arg 202 ;; 203 *) 204 echo >&2 "$0: Too many unsigned long int arguments for syscall ($strong $weak)" 205 exit 2 206 esac 207 done 208 209 # Make sure only the first syscall rule is used, if multiple dirs 210 # define the same syscall. 211 echo '' 212 echo "#### CALL=$file NUMBER=$callnum ARGS=$args SOURCE=$srcfile" 213 214 # If there are versioned aliases the entry is only generated for the 215 # shared library, unless it is a default version. 216 any_versioned=f 217 shared_only=f 218 case $weak in 219 *@@*) any_versioned=t ;; 220 *@*) any_versioned=t shared_only=t ;; 221 esac 222 223 case x$srcfile"$callnum" in 224 x--) 225 # Undefined callnum for an extra syscall. 226 if [ x$caller != x- ]; then 227 if [ $noerrno != 0 ]; then 228 echo >&2 "$0: no number for $fileno, no-error syscall ($strong $weak)" 229 exit 2 230 fi 231 echo "unix-stub-syscalls += $strong $weak" 232 fi 233 ;; 234 x*-) ;; ### Do nothing for undefined callnum 235 x-*) 236 echo "ifeq (,\$(filter $file,\$(unix-syscalls)))" 237 238 if test $shared_only = t; then 239 # The versioned symbols are only in the shared library. 240 echo "ifneq (,\$(filter .os,\$(object-suffixes)))" 241 fi 242 # Accumulate the list of syscall files for this directory. 243 echo "unix-syscalls += $file" 244 test x$caller = x- || echo "unix-extra-syscalls += $file" 245 246 # Emit a compilation rule for this syscall. 247 if test $shared_only = t; then 248 # The versioned symbols are only in the shared library. 249 echo "shared-only-routines += $file" 250 echo "\$(objpfx)${file}.os: \\" 251 else 252 object_suffixes='$(object-suffixes)' 253 echo "\ 254\$(foreach p,\$(sysd-rules-targets),\ 255\$(foreach o,${object_suffixes},\$(objpfx)\$(patsubst %,\$p,$file)\$o)): \\" 256 fi 257 258 echo " \$(..)sysdeps/unix/make-syscalls.sh" 259 case x"$callnum" in 260 x_) 261 echo "\ 262 \$(make-target-directory) 263 (echo '/* Dummy module requested by syscalls.list */'; \\" 264 ;; 265 x*) 266 echo "\ 267 \$(make-target-directory) 268 (echo '#define SYSCALL_NAME $syscall'; \\ 269 echo '#define SYSCALL_NARGS $nargs'; \\ 270 echo '#define SYSCALL_ULONG_ARG_1 $ulong_arg_1'; \\ 271 echo '#define SYSCALL_ULONG_ARG_2 $ulong_arg_2'; \\ 272 echo '#define SYSCALL_SYMBOL $strong'; \\ 273 echo '#define SYSCALL_NOERRNO $noerrno'; \\ 274 echo '#define SYSCALL_ERRVAL $errval'; \\ 275 echo '#include <syscall-template.S>'; \\" 276 ;; 277 esac 278 279 # Append any weak aliases or versions defined for this syscall function. 280 emit_weak_aliases 281 282 # And finally, pipe this all into the compiler. 283 echo ' ) | $(compile-syscall) '"\ 284\$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS))" 285 286 if test $shared_only = t; then 287 # The versioned symbols are only in the shared library. 288 echo endif 289 fi 290 291 echo endif 292 ;; 293 esac 294 295done 296