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 |