| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 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 | # C: cancellable (i.e., this syscall is a cancellation point) | 
|  | 16 | # E: errno and return value are not set by the call | 
|  | 17 | # V: errno is not set, but errno or zero (success) is returned from the call | 
|  | 18 | # | 
|  | 19 | # Syscall Signature Key Letters: | 
|  | 20 | # | 
|  | 21 | # a: unchecked address (e.g., 1st arg to mmap) | 
|  | 22 | # b: non-NULL buffer (e.g., 2nd arg to read; return value from mmap) | 
|  | 23 | # B: optionally-NULL buffer (e.g., 4th arg to getsockopt) | 
|  | 24 | # f: buffer of 2 ints (e.g., 4th arg to socketpair) | 
|  | 25 | # F: 3rd arg to fcntl | 
|  | 26 | # i: scalar (any signedness & size: int, long, long long, enum, whatever) | 
|  | 27 | # I: 3rd arg to ioctl | 
|  | 28 | # n: scalar buffer length (e.g., 3rd arg to read) | 
|  | 29 | # N: pointer to value/return scalar buffer length (e.g., 6th arg to recvfrom) | 
|  | 30 | # p: non-NULL pointer to typed object (e.g., any non-void* arg) | 
|  | 31 | # P: optionally-NULL pointer to typed object (e.g., 2nd argument to gettimeofday) | 
|  | 32 | # s: non-NULL string (e.g., 1st arg to open) | 
|  | 33 | # S: optionally-NULL string (e.g., 1st arg to acct) | 
|  | 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 |  | 
|  | 41 | thisdir=$1; shift | 
|  | 42 |  | 
|  | 43 | echo '' | 
|  | 44 | echo \#### 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. | 
|  | 48 | sysdirs=`for dir in $sysdirs; do | 
|  | 49 | test $dir = $thisdir && break; echo $dir; done` | 
|  | 50 | echo \#### SYSDIRS = $sysdirs | 
|  | 51 |  | 
|  | 52 | # Get the list of system calls for this directory. | 
|  | 53 | calls=`sed 's/#.*$// | 
|  | 54 | /^[ 	]*$/d' $thisdir/syscalls.list` | 
|  | 55 |  | 
|  | 56 | calls=`echo "$calls" | | 
|  | 57 | while 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; | 
|  | 70 | done` | 
|  | 71 |  | 
|  | 72 | # Any calls left? | 
|  | 73 | test -n "$calls" || exit 0 | 
|  | 74 |  | 
|  | 75 | # This uses variables $weak, $strong, and $any_versioned. | 
|  | 76 | emit_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 'strong_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. | 
|  | 150 | echo "$calls" | | 
|  | 151 | while read file srcfile caller syscall args strong weak; do | 
|  | 152 |  | 
|  | 153 | vdso_syscall= | 
|  | 154 | case x"$syscall" in | 
|  | 155 | *:*@*) | 
|  | 156 | vdso_syscall="${syscall#*:}" | 
|  | 157 | syscall="${syscall%:*}" | 
|  | 158 | ;; | 
|  | 159 | esac | 
|  | 160 |  | 
|  | 161 | case x"$syscall" in | 
|  | 162 | x-) callnum=_ ;; | 
|  | 163 | *) | 
|  | 164 | # Figure out if $syscall is defined with a number in syscall.h. | 
|  | 165 | callnum=- | 
|  | 166 | eval `{ echo "#include <sysdep.h>"; | 
|  | 167 | echo "callnum=SYS_ify ($syscall)"; } | | 
|  | 168 | $asm_CPP -D__OPTIMIZE__ - | | 
|  | 169 | sed -n -e "/^callnum=.*$syscall/d" \ | 
|  | 170 | -e "/^\(callnum=\)[ 	]*\(.*\)/s//\1'\2'/p"` | 
|  | 171 | ;; | 
|  | 172 | esac | 
|  | 173 |  | 
|  | 174 | cancellable=0 | 
|  | 175 | noerrno=0 | 
|  | 176 | errval=0 | 
|  | 177 | case $args in | 
|  | 178 | C*) cancellable=1; args=`echo $args | sed 's/C:\?//'`;; | 
|  | 179 | E*) noerrno=1; args=`echo $args | sed 's/E:\?//'`;; | 
|  | 180 | V*) errval=1; args=`echo $args | sed 's/V:\?//'`;; | 
|  | 181 | esac | 
|  | 182 |  | 
|  | 183 | # Derive the number of arguments from the argument signature | 
|  | 184 | case $args in | 
|  | 185 | [0-9]) nargs=$args;; | 
|  | 186 | ?:) nargs=0;; | 
|  | 187 | ?:?) nargs=1;; | 
|  | 188 | ?:??) nargs=2;; | 
|  | 189 | ?:???) nargs=3;; | 
|  | 190 | ?:????) nargs=4;; | 
|  | 191 | ?:?????) nargs=5;; | 
|  | 192 | ?:??????) nargs=6;; | 
|  | 193 | ?:???????) nargs=7;; | 
|  | 194 | ?:????????) nargs=8;; | 
|  | 195 | ?:?????????) nargs=9;; | 
|  | 196 | esac | 
|  | 197 |  | 
|  | 198 | # Make sure only the first syscall rule is used, if multiple dirs | 
|  | 199 | # define the same syscall. | 
|  | 200 | echo '' | 
|  | 201 | echo "#### CALL=$file NUMBER=$callnum ARGS=$args SOURCE=$srcfile" | 
|  | 202 |  | 
|  | 203 | # If there are versioned aliases the entry is only generated for the | 
|  | 204 | # shared library, unless it is a default version. | 
|  | 205 | any_versioned=f | 
|  | 206 | shared_only=f | 
|  | 207 | case $weak in | 
|  | 208 | *@@*) any_versioned=t ;; | 
|  | 209 | *@*) any_versioned=t shared_only=t ;; | 
|  | 210 | esac | 
|  | 211 |  | 
|  | 212 | case x$srcfile"$callnum" in | 
|  | 213 | x--) | 
|  | 214 | # Undefined callnum for an extra syscall. | 
|  | 215 | if [ x$caller != x- ]; then | 
|  | 216 | if [ $noerrno != 0 ]; then | 
|  | 217 | echo >&2 "$0: no number for $fileno, no-error syscall ($strong $weak)" | 
|  | 218 | exit 2 | 
|  | 219 | fi | 
|  | 220 | echo "unix-stub-syscalls += $strong $weak" | 
|  | 221 | fi | 
|  | 222 | ;; | 
|  | 223 | x*-) ;; ### Do nothing for undefined callnum | 
|  | 224 | x-*) | 
|  | 225 | echo "ifeq (,\$(filter $file,\$(unix-syscalls)))" | 
|  | 226 |  | 
|  | 227 | if test $shared_only = t; then | 
|  | 228 | # The versioned symbols are only in the shared library. | 
|  | 229 | echo "ifneq (,\$(filter .os,\$(object-suffixes)))" | 
|  | 230 | fi | 
|  | 231 | # Accumulate the list of syscall files for this directory. | 
|  | 232 | echo "unix-syscalls += $file" | 
|  | 233 | test x$caller = x- || echo "unix-extra-syscalls += $file" | 
|  | 234 |  | 
|  | 235 | # Emit a compilation rule for this syscall. | 
|  | 236 | if test $shared_only = t; then | 
|  | 237 | # The versioned symbols are only in the shared library. | 
|  | 238 | echo "shared-only-routines += $file" | 
|  | 239 | test -n "$vdso_syscall" || echo "\$(objpfx)${file}.os: \\" | 
|  | 240 | else | 
|  | 241 | object_suffixes='$(object-suffixes)' | 
|  | 242 | test -z "$vdso_syscall" || object_suffixes='$(object-suffixes-noshared)' | 
|  | 243 | echo "\ | 
|  | 244 | \$(foreach p,\$(sysd-rules-targets),\ | 
|  | 245 | \$(foreach o,${object_suffixes},\$(objpfx)\$(patsubst %,\$p,$file)\$o)): \\" | 
|  | 246 | fi | 
|  | 247 |  | 
|  | 248 | echo "		\$(..)sysdeps/unix/make-syscalls.sh" | 
|  | 249 | case x"$callnum" in | 
|  | 250 | x_) | 
|  | 251 | echo "\ | 
|  | 252 | \$(make-target-directory) | 
|  | 253 | (echo '/* Dummy module requested by syscalls.list */'; \\" | 
|  | 254 | ;; | 
|  | 255 | x*) | 
|  | 256 | echo "\ | 
|  | 257 | \$(make-target-directory) | 
|  | 258 | (echo '#define SYSCALL_NAME $syscall'; \\ | 
|  | 259 | echo '#define SYSCALL_NARGS $nargs'; \\ | 
|  | 260 | echo '#define SYSCALL_SYMBOL $strong'; \\ | 
|  | 261 | echo '#define SYSCALL_CANCELLABLE $cancellable'; \\ | 
|  | 262 | echo '#define SYSCALL_NOERRNO $noerrno'; \\ | 
|  | 263 | echo '#define SYSCALL_ERRVAL $errval'; \\ | 
|  | 264 | echo '#include <syscall-template.S>'; \\" | 
|  | 265 | ;; | 
|  | 266 | esac | 
|  | 267 |  | 
|  | 268 | # Append any weak aliases or versions defined for this syscall function. | 
|  | 269 | emit_weak_aliases | 
|  | 270 |  | 
|  | 271 | # And finally, pipe this all into the compiler. | 
|  | 272 | echo '	) | $(compile-syscall) '"\ | 
|  | 273 | \$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS))" | 
|  | 274 |  | 
|  | 275 | if test -n "$vdso_syscall"; then | 
|  | 276 | # In the shared library, we're going to emit an IFUNC using a vDSO function. | 
|  | 277 | # $vdso_syscall looks like "name@KERNEL_X.Y" where "name" is the symbol | 
|  | 278 | # name in the vDSO and KERNEL_X.Y is its symbol version. | 
|  | 279 | vdso_symbol="${vdso_syscall%@*}" | 
|  | 280 | vdso_symver="${vdso_syscall#*@}" | 
|  | 281 | vdso_symver=`echo "$vdso_symver" | sed 's/\./_/g'` | 
|  | 282 | cat <<EOF | 
|  | 283 |  | 
|  | 284 | \$(foreach p,\$(sysd-rules-targets),\$(objpfx)\$(patsubst %,\$p,$file).os): \\ | 
|  | 285 | \$(..)sysdeps/unix/make-syscalls.sh | 
|  | 286 | \$(make-target-directory) | 
|  | 287 | (echo '#include <dl-vdso.h>'; \\ | 
|  | 288 | echo 'extern void *${strong}_ifunc (void) __asm ("${strong}");'; \\ | 
|  | 289 | echo 'void *'; \\ | 
|  | 290 | echo '${strong}_ifunc (void)'; \\ | 
|  | 291 | echo '{'; \\ | 
|  | 292 | echo '  PREPARE_VERSION_KNOWN (symver, ${vdso_symver});'; \\ | 
|  | 293 | echo '  return _dl_vdso_vsym ("${vdso_symbol}", &symver);'; \\ | 
|  | 294 | echo '}'; \\ | 
|  | 295 | echo 'asm (".type ${strong}, %gnu_indirect_function");'; \\ | 
|  | 296 | EOF | 
|  | 297 | # This is doing "hidden_def (${strong})", but the compiler | 
|  | 298 | # doesn't know that we've defined ${strong} in the same file, so | 
|  | 299 | # we can't do it the normal way. | 
|  | 300 | cat <<EOF | 
|  | 301 | echo 'asm (".globl __GI_${strong}");'; \\ | 
|  | 302 | echo 'asm ("__GI_${strong} = ${strong}");'; \\ | 
|  | 303 | EOF | 
|  | 304 | emit_weak_aliases | 
|  | 305 | cat <<EOF | 
|  | 306 | ) | \$(compile-stdin.c) \ | 
|  | 307 | \$(foreach p,\$(patsubst %$file,%,\$(basename \$(@F))),\$(\$(p)CPPFLAGS)) | 
|  | 308 | EOF | 
|  | 309 | fi | 
|  | 310 |  | 
|  | 311 | if test $shared_only = t; then | 
|  | 312 | # The versioned symbols are only in the shared library. | 
|  | 313 | echo endif | 
|  | 314 | fi | 
|  | 315 |  | 
|  | 316 | echo endif | 
|  | 317 | ;; | 
|  | 318 | esac | 
|  | 319 |  | 
|  | 320 | done |