status-im / nim-bearssl

BearSSL wrapper in Nim
Other
40 stars 8 forks source link

BearSSL's automatic static linking trimming doesn't work completely #53

Open iffy opened 10 months ago

iffy commented 10 months ago

BearSSL advertises:

A static linking model in which only algorithms that are actually used get pulled into the linked binary. This is done through appropriate usage of function pointers; there is no need to recompile BearSSL with specific preprocessor options to obtain such a trimming.

And in another place

BearSSL is pluggable, so what a given SSL client or server engine supports depends on which algorithms were configured into it. From a programming point of view, each algorithm is configured by setting a pointer to the relevant implementation into the engine context; referencing that implementation means that, at link time, the corresponding code will be pulled into the produced binary, along with all its dependencies.

When wrapped in nim-bearssl, though, it seems like some of the pluggable-ness is gone. For instance, compiling the following, which only uses MD5 still includes symbols for SHA algorithms:

import std/os
import bearssl/hash

let inp = paramStr(1)
var
  ctx = Md5Context()
  res: array[md5SIZE, uint8]

md5Init(ctx)
md5Update(ctx, inp.cstring, uint inp.len)
md5Out(ctx, addr res[0])
echo $res
$ nim c samp && nm samp | grep br_sha
000000010001c7b0 S _br_sha1_IV
0000000100008bb0 T _br_sha1_init
0000000100008d10 T _br_sha1_out
00000001000080f0 T _br_sha1_round
0000000100008f30 T _br_sha1_set_state
0000000100008ef0 T _br_sha1_state
0000000100008c10 T _br_sha1_update
000000010001e120 S _br_sha1_vtable
000000010001cad0 S _br_sha224_IV
000000010000afc0 T _br_sha224_init
000000010000b150 T _br_sha224_out
000000010000b360 T _br_sha224_set_state
000000010000b320 T _br_sha224_state
000000010000b020 T _br_sha224_update
000000010001e1c8 S _br_sha224_vtable
000000010001caf0 S _br_sha256_IV
000000010000b3b0 T _br_sha256_init
000000010000b410 T _br_sha256_out
000000010001e200 S _br_sha256_vtable
000000010000a3a0 T _br_sha2small_round
0000000100008fe0 T _br_sha384_init
0000000100009170 T _br_sha384_out
00000001000093e0 T _br_sha384_set_state
00000001000093a0 T _br_sha384_state
0000000100009040 T _br_sha384_update
000000010001e158 S _br_sha384_vtable
0000000100009430 T _br_sha512_init
0000000100009490 T _br_sha512_out
000000010001e190 S _br_sha512_vtable

Or in this example, nothing from BearSSL is used, yet the resulting binary contains all of BearSSL:

import bearssl
import bearssl/hash
echo "foo"
$ nim c samp && nm samp | grep br_
000000010008f2c0 S _br_aes_S
000000010000a1c0 T _br_aes_big_cbcdec_init
000000010000a220 T _br_aes_big_cbcdec_run
0000000100099130 S _br_aes_big_cbcdec_vtable
000000010000a330 T _br_aes_big_cbcenc_init
000000010000a390 T _br_aes_big_cbcenc_run
0000000100099150 S _br_aes_big_cbcenc_vtable
000000010000a470 T _br_aes_big_ctr_init
000000010000a4d0 T _br_aes_big_ctr_run
0000000100099170 S _br_aes_big_ctr_vtable
000000010000a710 T _br_aes_big_ctrcbc_ctr
...
0000000100068020 t _br_x509_minimal_set_hash
000000010006f4c0 t _br_x509_minimal_set_hash
0000000100067fd0 t _br_x509_minimal_set_rsa
000000010006f3d0 t _br_x509_minimal_set_rsa
0000000100099bd8 S _br_x509_minimal_vtable

I'm not complaining, just observing. I'm even willing to submit a PR to enhance this. While in my case this isn't a critical feature, it certainly would be nice to have smaller binaries.

Is it because of the {.used.} pragma I see in various places? Or something else?

arnetheduck commented 9 months ago

Is it because of the {.used.} pragma I see in various places? Or something else?

{.used.} should not affect this at all - that's a pure nim-side construct - I too would be interested to know in depth what is causing the symbol references - ie it could be that some constant or semi-constant is getting generated somewhere that touches the symbols causing them to be included but this would require some digging. Happy to look at a PR if you find something!