Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

missing symbols for no_std target #119

Closed
laanwj opened this issue Jun 10, 2019 · 12 comments
Closed

missing symbols for no_std target #119

laanwj opened this issue Jun 10, 2019 · 12 comments

Comments

@laanwj
Copy link
Contributor

laanwj commented Jun 10, 2019

(looks like there's some overlap with #114)

I'm trying to build rust-secp256k1 for a bare-metal RISC-V platform, I've built and installed a compatible toolchain using crosstool-ng and do

CC="${HOME}/x-tools/riscv64-unknown-elf/bin/riscv64-unknown-elf-gcc" cargo build --release

However, I get the following missing symbol errors:

   Compiling secp256k1-test v0.1.0 (/home/user/maixgo/k210-sdk-stuff/rust/secp256k1-test)
error: linking with `rust-lld` failed: exit code: 1
  |
...
  = note: rust-lld: error: undefined symbol: _impure_ptr
          >>> referenced by reent.h:814 (/home/user/x-tools/riscv64-unknown-elf/riscv64-unknown-elf/sys-include/sys/reent.h:814)
          >>>               secp256k1.o:(default_error_callback_fn) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: fprintf
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(default_error_callback_fn) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: _impure_ptr
          >>> referenced by reent.h:814 (/home/user/x-tools/riscv64-unknown-elf/riscv64-unknown-elf/sys-include/sys/reent.h:814)
          >>>               secp256k1.o:(default_illegal_callback_fn) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: fprintf
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(default_illegal_callback_fn) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: free
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: free
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: free
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_odd_multiples_table_storage_var.constprop.31) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_gen_context_build) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_gen_context_build) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_gen_context_build) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: free
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_gen_context_build) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: free
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_ecmult_gen_context_build) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: malloc
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_context_create) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: _impure_ptr
          >>> referenced by reent.h:814 (/home/user/x-tools/riscv64-unknown-elf/riscv64-unknown-elf/sys-include/sys/reent.h:814)
          >>>               secp256k1.o:(secp256k1_context_create) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: undefined symbol: fprintf
          >>> referenced by secp256k1.c
          >>>               secp256k1.o:(secp256k1_context_create) in archive /home/user/maixgo/k210-sdk-stuff/rust/target/riscv64gc-unknown-none-elf/release/deps/libsecp256k1-ad9949776962da29.rlib
          
          rust-lld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
          

error: aborting due to previous error

error: Could not compile `secp256k1-test`.

To learn more, run the command again with --verbose.

So I guess the malloc/free is due to context allocation/deallocation and will be solved by updating the secp256k1 tree for bitcoin-core/secp256k1#566 bitcoin-core/secp256k1#614 etc.
THe _impure_ptr is more confusing to me.

Edit: Ok, looks like _impure_ptr is related, looking at the disassembly it's always used to get to stderr, the first parameter of fprintf, usually invoked through CHECK.

@TheBlueMatt
Copy link
Member

TheBlueMatt commented Jun 10, 2019 via email

@TheBlueMatt
Copy link
Member

TheBlueMatt commented Jun 10, 2019 via email

@elichai
Copy link
Member

elichai commented Jun 10, 2019

Can you try that using #115 and/or #116?
#115 should solve the fprintf and #116 should solve the malloc/free
I might test that myself later today if you don't have time

@elichai
Copy link
Member

elichai commented Jun 10, 2019

Trying to recreate this doesn't work well for me :/
I think i'll need to get riscv64-unknown-elf-gcc too. because running this passes for me:
cargo build --release --target riscv64gc-unknown-none-elf --no-default-features

@elichai
Copy link
Member

elichai commented Jun 10, 2019

Ok, I installed the riscv64 crostools and ran CC="${HOME}/x-tools/riscv64-unknown-elf/bin/riscv64-unknown-elf-gcc" cargo build --release --no-default-features --target riscv64gc-unknown-none-elf and it still compiles fine (on master)
can you point me to your code here? secp256k1-test it probably only fails on link time when trying to make a binary

@laanwj
Copy link
Contributor Author

laanwj commented Jun 11, 2019

nostd implies no malloc/free, which we don't yet support. I believe there's some work upstream that will enable this eventually.

Very true! With malloc/free it works fine. I've run the secp256k1 tests on this device (except the ones that need >8MB memory) after compiling it using the C SDK, which has a tiny libc. However, the rust embedded environment doesn't have them.

I know it's possible to define a custom allocator and heap on embedded (#![allocator]) but I don't think this will provide those functions to C.

I was confused because the crate advertises "makes no allocations (except in unit tests) for efficiency and use in freestanding implementations". But I understand this refers to the crate itself, not the code it embeds.

can you point me to your code here? secp256k1-test

Sure, but the code doesn't do anything at all, it just imports secp256k1 and makes a context. It's a compile test, not a run test.

#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![no_std]
#![no_main]

use k210_hal::pac;
use k210_hal::prelude::*;
use k210_hal::stdout::Stdout;
use riscv_rt::entry;
use k210_shared::soc::sleep::usleep;
use secp256k1::{Secp256k1, Message, SecretKey, PublicKey};

#[entry]
fn main() -> ! {
    let p = pac::Peripherals::take().unwrap();
    let clocks = k210_hal::clock::Clocks::new();

    usleep(200000);

    // Configure UART
    let serial = p.UARTHS.constrain(115_200.bps(), &clocks);
    let (mut tx, _) = serial.split();

    let mut stdout = Stdout(&mut tx);

    writeln!(stdout, "testing").unwrap();

    let secp = Secp256k1::new();
    let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
    let public_key = PublicKey::from_secret_key(&secp, &secret_key);
    let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");

    let sig = secp.sign(&message, &secret_key);
    assert!(secp.verify(&message, &sig, &public_key).is_ok());

    loop {
    }
}

it probably only fails on link time when trying to make a binary

Yes, you're right—the part that fails is linking the rust code to the C code, to create a binary image for uploading to the device. Compilation works fine.

Can you try that using #115 and/or #116?

I'm going to try this.

@laanwj
Copy link
Contributor Author

laanwj commented Jun 11, 2019

Ok, I installed the riscv64 crostools and ran

BTW if you build your rv64 toolchain with crosstool-ng, and want to be able to link against rust code, make sure that you set

CT_ARCH_ARCH="rv64gc"
CT_ARCH_ABI="lp64"

As rust's linker only supports softfloat at this point, and I think the default for the architecture is hardfloat (rust-lang/rust#60012)

@elichai
Copy link
Member

elichai commented Jun 11, 2019

If your tiny libc has malloc(I think aligned_alloc will be better but not sure) and free then you can implement GlobalAlloc with bindings to that libc (example of someone doing that: https://github.com/baidu/rust-sgx-sdk/blob/master/sgx_alloc/src/lib.rs#L123)

Altough I see that the linker complained also about malloc and free so either your libc doesn't have it or you didn't link against it

p.s. you can even implement your own fprint using the k210_hal::stdout::Stdout

@laanwj
Copy link
Contributor Author

laanwj commented Jun 11, 2019

If your tiny libc has malloc(I think aligned_alloc will be better but not sure) and free then you can implement GlobalAlloc with bindings to that libc (example of someone doing that: https://github.com/baidu/rust-sgx-sdk/blob/master/sgx_alloc/src/lib.rs#L123)

Thanks! But I'd really, really prefer to not link against Kendryte's SDK, I just want to use secp256k1 in my rust-based firmware. (I've already reimplemented most of their peripheral access code in rust, it would be a shame to need to link against it just for memory allocation)

But good point that I can just implement my own malloc and free with extern "C" from rust. They could be trivial and simply return a moving pointer like sbrk.

p.s. you can even implement your own fprint using the k210_hal::stdout::Stdout

👍

@elichai
Copy link
Member

elichai commented Jun 11, 2019

@laanwj Cool, So either do that or #116 with default-features=false should have no malloc, free or fprintf (#115 just have no fprintf) but the API is a bit different there (you need to provide your own buffer, either by manually allocating or by using the stack)

@apoelstra
Copy link
Member

@laanwj does everything work now that #125 is in?

@apoelstra
Copy link
Member

Should be fixed in 0.14.0.

@laanwj
Copy link
Contributor Author

laanwj commented Aug 7, 2019

yes, thank you !

@laanwj laanwj closed this as completed Aug 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants