aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/internal/boring/build-goboring.sh
blob: c43fad24e8b14a1e12d35803053edbc45a68fc08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/bin/bash
# Copyright 2020 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

# Do not run directly; run build.sh, which runs this in Docker.
# This script builds goboringcrypto's syso, after boringssl has been built.

export TERM=dumb

set -e
set -x
id
date
export LANG=C
unset LANGUAGE

case $(uname -m) in
x86_64)  export GOARCH=amd64 ;;
aarch64) export GOARCH=arm64 ;;
*)
	echo 'unknown uname -m:' $(uname -m) >&2
	exit 2
esac

export CGO_ENABLED=0

# Build and run test C++ program to make sure goboringcrypto.h matches openssl/*.h.
# Also collect list of checked symbols in syms.txt
set -e
cd /boring/godriver
cat >goboringcrypto.cc <<'EOF'
#include <cassert>
#include "goboringcrypto0.h"
#include "goboringcrypto1.h"
#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;}
#define check_func(f) { auto x = f; x = _goboringcrypto_ ## f ; }
#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;}
int main() {
int ret = 0;
#include "goboringcrypto.x"
return ret;
}
EOF

cat >boringx.awk <<'EOF'
BEGIN {
	exitcode = 0
}

# Ignore comments, #includes, blank lines.
/^\/\// || /^#/ || NF == 0 { next }

# Ignore unchecked declarations.
/\/\*unchecked/ { next }

# Check enum values.
!enum && ($1 == "enum" || $2 == "enum") && $NF == "{" {
	enum = 1
	next
}
enum && $1 == "};" {
	enum = 0
	next
}
enum && /^}.*;$/ {
	enum = 0
	next
}
enum && NF == 3 && $2 == "=" {
	name = $1
	sub(/^GO_/, "", name)
	val = $3
	sub(/,$/, "", val)
	print "check_value(" name ", " val ")" > "goboringcrypto.x"
	next
}
enum {
	print FILENAME ":" NR ": unexpected line in enum: " $0 > "/dev/stderr"
	exitcode = 1
	next
}

# Check struct sizes.
/^typedef struct / && $NF ~ /^GO_/ {
	name = $NF
	sub(/^GO_/, "", name)
	sub(/;$/, "", name)
	print "check_size(" name ")" > "goboringcrypto.x"
	next
}

# Check function prototypes.
/^(const )?[^ ]+ \**_goboringcrypto_.*\(/ {
	name = $2
	if($1 == "const")
		name = $3
	sub(/^\**_goboringcrypto_/, "", name)
	sub(/\(.*/, "", name)
	print "check_func(" name ")" > "goboringcrypto.x"
	print name > "syms.txt"
	next
}

{
	print FILENAME ":" NR ": unexpected line: " $0 > "/dev/stderr"
	exitcode = 1
}

END {
	exit exitcode
}
EOF

cat >boringh.awk <<'EOF'
/^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next}
/typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print >"goboringcrypto1.h";next}
{gsub(/GO_/, ""); gsub(/enum go_/, "enum "); gsub(/go_point_conv/, "point_conv"); print >"goboringcrypto1.h"}
EOF

awk -f boringx.awk goboringcrypto.h # writes goboringcrypto.x
awk -f boringh.awk goboringcrypto.h # writes goboringcrypto[01].h

ls -l ../boringssl/include
clang++ -fPIC -I../boringssl/include -O2 -o a.out  goboringcrypto.cc
./a.out || exit 2

# clang implements u128 % u128 -> u128 by calling __umodti3,
# which is in libgcc. To make the result self-contained even if linking
# against a different compiler version, link our own __umodti3 into the syso.
# This one is specialized so it only expects divisors below 2^64,
# which is all BoringCrypto uses. (Otherwise it will seg fault.)
cat >umod-amd64.s <<'EOF'
# tu_int __umodti3(tu_int x, tu_int y)
# x is rsi:rdi, y is rcx:rdx, return result is rdx:rax.
.globl __umodti3
__umodti3:
	# specialized to u128 % u64, so verify that
	test %rcx,%rcx
	jne 1f

	# save divisor
	movq %rdx, %r8

	# reduce top 64 bits mod divisor
	movq %rsi, %rax
	xorl %edx, %edx
	divq %r8

	# reduce full 128-bit mod divisor
	# quotient fits in 64 bits because top 64 bits have been reduced < divisor.
	# (even though we only care about the remainder, divq also computes
	# the quotient, and it will trap if the quotient is too large.)
	movq %rdi, %rax
	divq %r8

	# expand remainder to 128 for return
	movq %rdx, %rax
	xorl %edx, %edx
	ret

1:
	# crash - only want 64-bit divisor
	xorl %ecx, %ecx
	movl %ecx, 0(%ecx)
	jmp 1b

.section .note.GNU-stack,"",@progbits
EOF

cat >umod-arm64.c <<'EOF'
typedef unsigned int u128 __attribute__((mode(TI)));

static u128 div(u128 x, u128 y, u128 *rp) {
	int n = 0;
	while((y>>(128-1)) != 1 && y < x) {
		y<<=1;
		n++;
	}
	u128 q = 0;
	for(;; n--, y>>=1, q<<=1) {
		if(x>=y) {
			x -= y;
			q |= 1;
		}
		if(n == 0)
			break;
	}
	if(rp)
		*rp = x;
	return q;
}

u128 __umodti3(u128 x, u128 y) {
	u128 r;
	div(x, y, &r);
	return r;
}

u128 __udivti3(u128 x, u128 y) {
	return div(x, y, 0);
}
EOF

extra=""
case $GOARCH in
amd64)
	cp umod-amd64.s umod.s
	clang -c -o umod.o umod.s
	extra=umod.o
	;;
arm64)
	cp umod-arm64.c umod.c
	clang -c -o umod.o umod.c
	extra=umod.o
	;;
esac

# Prepare copy of libcrypto.a with only the checked functions renamed and exported.
# All other symbols are left alone and hidden.
echo BORINGSSL_bcm_power_on_self_test >>syms.txt
awk '{print "_goboringcrypto_" $0 }' syms.txt >globals.txt
awk '{print $0 " _goboringcrypto_" $0 }' syms.txt >renames.txt
objcopy --globalize-symbol=BORINGSSL_bcm_power_on_self_test \
	../boringssl/build/crypto/libcrypto.a libcrypto.a

# Link together bcm.o and libcrypto.a into a single object.
ld -r -nostdlib --whole-archive -o goboringcrypto.o libcrypto.a $extra

echo __umodti3 _goboringcrypto___umodti3 >>renames.txt
echo __udivti3 _goboringcrypto___udivti3 >>renames.txt
objcopy --remove-section=.llvm_addrsig goboringcrypto.o goboringcrypto1.o # b/179161016
objcopy --redefine-syms=renames.txt goboringcrypto1.o goboringcrypto2.o
objcopy --keep-global-symbols=globals.txt --strip-unneeded goboringcrypto2.o goboringcrypto_linux_$GOARCH.syso

# Done!
ls -l goboringcrypto_linux_$GOARCH.syso