build-goboring.sh raw

   1  #!/bin/bash
   2  # Copyright 2020 The Go Authors. All rights reserved.
   3  # Use of this source code is governed by a BSD-style
   4  # license that can be found in the LICENSE file.
   5  
   6  # Do not run directly; run build.sh, which runs this in Docker.
   7  # This script builds goboringcrypto's syso, after boringssl has been built.
   8  
   9  export TERM=dumb
  10  
  11  set -e
  12  set -x
  13  id
  14  date
  15  export LANG=C
  16  unset LANGUAGE
  17  
  18  case $(uname -m) in
  19  x86_64)  export GOARCH=amd64 ;;
  20  aarch64) export GOARCH=arm64 ;;
  21  *)
  22  	echo 'unknown uname -m:' $(uname -m) >&2
  23  	exit 2
  24  esac
  25  
  26  export CGO_ENABLED=0
  27  
  28  # Build and run test C++ program to make sure goboringcrypto.h matches openssl/*.h.
  29  # Also collect list of checked symbols in syms.txt
  30  set -e
  31  cd /boring/godriver
  32  cat >goboringcrypto.cc <<'EOF'
  33  #include <cassert>
  34  #include "goboringcrypto0.h"
  35  #include "goboringcrypto1.h"
  36  #define check_size(t) if(sizeof(t) != sizeof(GO_ ## t)) {printf("sizeof(" #t ")=%d, but sizeof(GO_" #t ")=%d\n", (int)sizeof(t), (int)sizeof(GO_ ## t)); ret=1;}
  37  #define check_func(f) { auto x = f; x = _goboringcrypto_ ## f ; }
  38  #define check_value(n, v) if(n != v) {printf(#n "=%d, but goboringcrypto.h defines it as %d\n", (int)n, (int)v); ret=1;}
  39  int main() {
  40  int ret = 0;
  41  #include "goboringcrypto.x"
  42  return ret;
  43  }
  44  EOF
  45  
  46  cat >boringx.awk <<'EOF'
  47  BEGIN {
  48  	exitcode = 0
  49  }
  50  
  51  # Ignore comments, #includes, blank lines.
  52  /^\/\// || /^#/ || NF == 0 { next }
  53  
  54  # Ignore unchecked declarations.
  55  /\/\*unchecked/ { next }
  56  
  57  # Check enum values.
  58  !enum && ($1 == "enum" || $2 == "enum") && $NF == "{" {
  59  	enum = 1
  60  	next
  61  }
  62  enum && $1 == "};" {
  63  	enum = 0
  64  	next
  65  }
  66  enum && /^}.*;$/ {
  67  	enum = 0
  68  	next
  69  }
  70  enum && NF == 3 && $2 == "=" {
  71  	name = $1
  72  	sub(/^GO_/, "", name)
  73  	val = $3
  74  	sub(/,$/, "", val)
  75  	print "check_value(" name ", " val ")" > "goboringcrypto.x"
  76  	next
  77  }
  78  enum {
  79  	print FILENAME ":" NR ": unexpected line in enum: " $0 > "/dev/stderr"
  80  	exitcode = 1
  81  	next
  82  }
  83  
  84  # Check struct sizes.
  85  /^typedef struct / && $NF ~ /^GO_/ {
  86  	name = $NF
  87  	sub(/^GO_/, "", name)
  88  	sub(/;$/, "", name)
  89  	print "check_size(" name ")" > "goboringcrypto.x"
  90  	next
  91  }
  92  
  93  # Check function prototypes.
  94  /^(const )?[^ ]+ \**_goboringcrypto_.*\(/ {
  95  	name = $2
  96  	if($1 == "const")
  97  		name = $3
  98  	sub(/^\**_goboringcrypto_/, "", name)
  99  	sub(/\(.*/, "", name)
 100  	print "check_func(" name ")" > "goboringcrypto.x"
 101  	print name > "syms.txt"
 102  	next
 103  }
 104  
 105  {
 106  	print FILENAME ":" NR ": unexpected line: " $0 > "/dev/stderr"
 107  	exitcode = 1
 108  }
 109  
 110  END {
 111  	exit exitcode
 112  }
 113  EOF
 114  
 115  cat >boringh.awk <<'EOF'
 116  /^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next}
 117  /typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print >"goboringcrypto1.h";next}
 118  {gsub(/GO_/, ""); gsub(/enum go_/, "enum "); gsub(/go_point_conv/, "point_conv"); print >"goboringcrypto1.h"}
 119  EOF
 120  
 121  awk -f boringx.awk goboringcrypto.h # writes goboringcrypto.x
 122  awk -f boringh.awk goboringcrypto.h # writes goboringcrypto[01].h
 123  
 124  ls -l ../boringssl/include
 125  clang++ -fPIC -I../boringssl/include -O2 -o a.out  goboringcrypto.cc
 126  ./a.out || exit 2
 127  
 128  # clang implements u128 % u128 -> u128 by calling __umodti3,
 129  # which is in libgcc. To make the result self-contained even if linking
 130  # against a different compiler version, link our own __umodti3 into the syso.
 131  # This one is specialized so it only expects divisors below 2^64,
 132  # which is all BoringCrypto uses. (Otherwise it will seg fault.)
 133  cat >umod-amd64.s <<'EOF'
 134  # tu_int __umodti3(tu_int x, tu_int y)
 135  # x is rsi:rdi, y is rcx:rdx, return result is rdx:rax.
 136  .globl __umodti3
 137  __umodti3:
 138  	# specialized to u128 % u64, so verify that
 139  	test %rcx,%rcx
 140  	jne 1f
 141  
 142  	# save divisor
 143  	movq %rdx, %r8
 144  
 145  	# reduce top 64 bits mod divisor
 146  	movq %rsi, %rax
 147  	xorl %edx, %edx
 148  	divq %r8
 149  
 150  	# reduce full 128-bit mod divisor
 151  	# quotient fits in 64 bits because top 64 bits have been reduced < divisor.
 152  	# (even though we only care about the remainder, divq also computes
 153  	# the quotient, and it will trap if the quotient is too large.)
 154  	movq %rdi, %rax
 155  	divq %r8
 156  
 157  	# expand remainder to 128 for return
 158  	movq %rdx, %rax
 159  	xorl %edx, %edx
 160  	ret
 161  
 162  1:
 163  	# crash - only want 64-bit divisor
 164  	xorl %ecx, %ecx
 165  	movl %ecx, 0(%ecx)
 166  	jmp 1b
 167  
 168  .section .note.GNU-stack,"",@progbits
 169  EOF
 170  
 171  cat >umod-arm64.c <<'EOF'
 172  typedef unsigned int u128 __attribute__((mode(TI)));
 173  
 174  static u128 div(u128 x, u128 y, u128 *rp) {
 175  	int n = 0;
 176  	while((y>>(128-1)) != 1 && y < x) {
 177  		y<<=1;
 178  		n++;
 179  	}
 180  	u128 q = 0;
 181  	for(;; n--, y>>=1, q<<=1) {
 182  		if(x>=y) {
 183  			x -= y;
 184  			q |= 1;
 185  		}
 186  		if(n == 0)
 187  			break;
 188  	}
 189  	if(rp)
 190  		*rp = x;
 191  	return q;
 192  }
 193  
 194  u128 __umodti3(u128 x, u128 y) {
 195  	u128 r;
 196  	div(x, y, &r);
 197  	return r;
 198  }
 199  
 200  u128 __udivti3(u128 x, u128 y) {
 201  	return div(x, y, 0);
 202  }
 203  EOF
 204  
 205  extra=""
 206  case $GOARCH in
 207  amd64)
 208  	cp umod-amd64.s umod.s
 209  	clang -c -o umod.o umod.s
 210  	extra=umod.o
 211  	;;
 212  arm64)
 213  	cp umod-arm64.c umod.c
 214  	clang -c -o umod.o umod.c
 215  	extra=umod.o
 216  	;;
 217  esac
 218  
 219  # Prepare copy of libcrypto.a with only the checked functions renamed and exported.
 220  # All other symbols are left alone and hidden.
 221  echo BORINGSSL_bcm_power_on_self_test >>syms.txt
 222  awk '{print "_goboringcrypto_" $0 }' syms.txt >globals.txt
 223  awk '{print $0 " _goboringcrypto_" $0 }' syms.txt >renames.txt
 224  objcopy --globalize-symbol=BORINGSSL_bcm_power_on_self_test \
 225  	../boringssl/build/crypto/libcrypto.a libcrypto.a
 226  
 227  # Link together bcm.o and libcrypto.a into a single object.
 228  ld -r -nostdlib --whole-archive -o goboringcrypto.o libcrypto.a $extra
 229  
 230  echo __umodti3 _goboringcrypto___umodti3 >>renames.txt
 231  echo __udivti3 _goboringcrypto___udivti3 >>renames.txt
 232  objcopy --remove-section=.llvm_addrsig goboringcrypto.o goboringcrypto1.o # b/179161016
 233  objcopy --redefine-syms=renames.txt goboringcrypto1.o goboringcrypto2.o
 234  objcopy --keep-global-symbols=globals.txt --strip-unneeded goboringcrypto2.o goboringcrypto_linux_$GOARCH.syso
 235  
 236  # Done!
 237  ls -l goboringcrypto_linux_$GOARCH.syso
 238