linking against ipv4 module fails with missing checksum symbol
yomimono opened this issue · 10 comments
This is visible in the Travis output for #320 , but I've reproduced it locally as well:
home/dothraki/.opam/4.05.0+trunk+afl/lib/tcpip/ipv4/tcpip_ipv4.a(ipv4_packet.o): In function `camlIpv4_packet__unsafe_fill_1734':
/home/dothraki/.opam/4.05.0+trunk+afl/build/tcpip.3.1.4/_build/default/src/ipv4/ipv4_packet.ml:59: undefined reference to `caml_tcpip_ones_complement_checksum'
/home/dothraki/.opam/4.05.0+trunk+afl/lib/tcpip/ipv4/tcpip_ipv4.a(ipv4_packet.o): In function `camlIpv4_packet__check_1879':
/home/dothraki/.opam/4.05.0+trunk+afl/build/tcpip.3.1.4/_build/default/src/ipv4/ipv4_packet.ml:145: undefined reference to `caml_tcpip_ones_complement_checksum_list'
/home/dothraki/.opam/4.05.0+trunk+afl/lib/tcpip/tcpip.a(tcpip_checksum.o): In function `camlTcpip_checksum__fun_1277':
:(.text+0x37): undefined reference to `caml_tcpip_ones_complement_checksum_list'
/home/dothraki/.opam/4.05.0+trunk+afl/lib/tcpip/tcpip.a(tcpip_checksum.o): In function `camlTcpip_checksum__fun_1279':
:(.text+0x87): undefined reference to `caml_tcpip_ones_complement_checksum'
/home/dothraki/.opam/4.05.0+trunk+afl/lib/tcpip/tcpip.a(tcpip_checksum.o): In function `camlTcpip_checksum__2':
:(.data+0x58): undefined reference to `caml_tcpip_ones_complement_checksum_list'
:(.data+0x60): undefined reference to `caml_tcpip_ones_complement_checksum'
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
Command exited with code 2.
pkg.ml: [ERROR] cmd ['ocamlbuild' '-use-ocamlfind' '-classic-display' '-tag' 'debug'
'-build-dir' '_build' 'pkg/META' 'CHANGES.md' 'LICENSE.md' 'README.md'
'src/fuzz_ethif.native' 'src/fuzz_ipv4.native' 'src/fuzz_icmpv4.native'
'src/fuzz_tcp.native' 'src/fuzz_udp.native']: exited with 10
Any clues on where to start investigating this would be appreciated. It blocks fuzz testing the tcp stack with crowbar.
This is using the trunk version of tcpip, so it's probably due to the port to jbuilder. I'll look at this shortly.
It looks like a depedency on tcpip.unix
is missing from the binary being built. However, where is it being built? I cant find a PR with the fuzz testing branch
Yes, that's because crowbar is not released, so adding a dependency on it seemed unwise. There is code playing with it in https://github.com/yomimono/crowbar .
Sorry, https://GitHub.com/yomimono/somerandompacket ; forgive the spam.
Including tcpip.unix
fixes this for unix, but the corresponding tcpip.xen
doesn't help when building MirageOS unikernels targeting non-Unix. Here's the relevant bit of an attempt to build something with mirage configure -t xen
, after tweaking mirage
to always include tcpip.xen
when it'll be required for checksums:
ocamlfind ocamlopt -c -g -g -bin-annot -safe-string -principal -strict-sequence -package tcpip.xen -package tcpip.udp -package tcpip.tcp -package tcpip.stack-direct -package tcpip.ipv4 -package tcpip.icmpv4 -package tcpip.ethif -package tcpip.arpv4 -package tcpip -package nocrypto.mirage -package nocrypto -package mirage-xen -package mirage-types-lwt -package mirage-types -package mirage-runtime -package mirage-random -package mirage-net-xen -package mirage-logs -package mirage-http -package mirage-console-xen -package mirage-conduit -package mirage-clock-freestanding -package mirage-bootvar-xen -package mirage-block-ramdisk -package lwt -package logs-syslog.mirage -package logs-syslog -package io-page -package functoria-runtime -predicates mirage_xen -w A-4-41-42-44 -color always -o main.cmx main.ml
ocamlfind ocamlopt -g -dontlink unix -dontlink str -dontlink num -dontlink threads -linkpkg -output-obj -package tcpip.xen -package tcpip.udp -package tcpip.tcp -package tcpip.stack-direct -package tcpip.ipv4 -package tcpip.icmpv4 -package tcpip.ethif -package tcpip.arpv4 -package tcpip -package nocrypto.mirage -package nocrypto -package mirage-xen -package mirage-types-lwt -package mirage-types -package mirage-runtime -package mirage-random -package mirage-net-xen -package mirage-logs -package mirage-http -package mirage-console-xen -package mirage-conduit -package mirage-clock-freestanding -package mirage-bootvar-xen -package mirage-block-ramdisk -package lwt -package logs-syslog.mirage -package logs-syslog -package io-page -package functoria-runtime -predicates mirage_xen key_gen.cmx static1.cmx unikernel.cmx main.cmx -o main.native.o
_build/main.native.o: In function `camlIcmpv4_packet__unsafe_fill_1855':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/icmp/icmpv4_packet.ml:98: undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlIpv4_packet__unsafe_fill_1727':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/ipv4/ipv4_packet.ml:59: undefined reference to `caml_tcpip_ones_complement_checksum'
_build/main.native.o: In function `camlIpv4_packet__check_1871':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/ipv4/ipv4_packet.ml:145: undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlIpv4_common__adjust_output_header_1199':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/ipv4/ipv4_common.ml:9: undefined reference to `caml_tcpip_ones_complement_checksum'
_build/main.native.o: In function `camlIpv4_common__checksum_1660':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/ipv4/ipv4_common.ml:40: undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlTcp__Tcp_packet__unsafe_fill_1648':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/tcp/tcp_packet.ml:102: undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlUdp_packet__unsafe_fill_1539':
/home/dothraki/.opam/4.04.2/build/tcpip.3.2.0/_build/default/src/udp/udp_packet.ml:58: undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlTcpip_checksum__fun_1272':
(.text+0x182f1a): undefined reference to `caml_tcpip_ones_complement_checksum_list'
_build/main.native.o: In function `camlTcpip_checksum__fun_1274':
(.text+0x182f4a): undefined reference to `caml_tcpip_ones_complement_checksum'
_build/main.native.o: In function `camlTcpip_checksum__2':
:(.data+0x13b1c0): undefined reference to `caml_tcpip_ones_complement_checksum_list'
:(.data+0x13b1c8): undefined reference to `caml_tcpip_ones_complement_checksum'
run ['ld' '-d' '-static' '-nostdlib' '_build/main.native.o'
'-L/home/dothraki/.opam/4.04.2/lib/io-page-xen' '-lio_page_xen_stubs'
'-L/home/dothraki/.opam/4.04.2/lib/zarith' '-lzarith-xen'
'-L/home/dothraki/.opam/4.04.2/lib/gmp-xen' '-lgmp-xen'
'-L/home/dothraki/.opam/4.04.2/lib/nocrypto'
'-lnocrypto_stubs+mirage-xen'
'-L/home/dothraki/.opam/4.04.2/lib/mirage-entropy'
'-lmirage-entropy_stubs+mirage-xen' '-L/home/dothraki/.opam/4.04.2/lib'
'-L/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/minios-xen'
'/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/mirage-xen/libxencamlbindings.a'
'/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/mirage-xen-ocaml/libxenasmrun.a'
'/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/mirage-xen-ocaml/libxenotherlibs.a'
'/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/mirage-xen-posix/libxenposix.a'
'-lopenlibm' '-lminios'
'-T/home/dothraki/.opam/4.04.2/lib/pkgconfig/../../lib/minios-xen/libminios.lds'
'-m' 'elf_x86_64' '-lx86_64' '-o' 'all_devices.xen']: exited with 1
Makefile:18: recipe for target 'build' failed
make: *** [build] Error 1
You can see that -package tcpip.xen
is invoked, but it doesn't do us any good.
This reproduces for me.
In the very short term I think we need to add the xen_linkopts
back to the META
file. I'll take a quick look.
IMHO the handling of the checksum stubs is annoyingly complicated. I'll try to summarise how I think it currently works (-- let me know if you spot a mistake) (I'm writing this to force myself to page it back in -- feel free to ignore)
- on unix we use the normal OCaml mechanism: the stubs are associated with the OCaml objects and the
ocamlopt
invocation links them into the final binary - on Xen we perform the final link ourselves in the
mirage
tool, and rather than query the OCaml objects to discover the stubs (see mirage/mirage#832) we add a customxen_linkopts
field inside theMETA
file which is used by themirage
tool to pull in the objects - on Solo5 we have a customised copy of the stubs in the base platform library which is unconditionally linked
I think we've not pushed through any of these models to all libraries * all backends because they all seem a bit odd, leaving us in an inconsistent state.
I think the current consensus long-term view is that we should cross-compile everything (including OCaml code) for each backend that the user has selected to avoid future problems and use the regular OCaml mechanism to link stubs rather than a custom one. I hope that the jbuilder "workspace" concept will help us -- we can build everything n
times with different flags. The C stubs would then live in the same repo as the OCaml code, perhaps with #ifdef
s to use the different low-level platform C APIs? I guess the small set of stubs that are portable across backends are either pure functions (like crypto and checksums) or bindings to things like posix_memalign
. The former doesn't require an #ifdef
and the latter... maybe we should standardise the posix_memalign
interface at the C level anyway.
OK, I got stuck -- see my attempt at #332. If I hand-edit the META
file to put the xen_linkopts
inside the package "xen"
block then it works. I don't know how to achieve a similar effect at the top-level in the META
file.
One option is to split tcpip.xen
out into tcpip-xen
like we did for io-page-xen
. Another option is to put some more special-case directory magic into the mirage
tool.
I've added that change to the PR at mirage/mirage#856 .