Skip to content

ld symbols not found on c-style FFI union #30290

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

Closed
daschl opened this issue Dec 9, 2015 · 5 comments
Closed

ld symbols not found on c-style FFI union #30290

daschl opened this issue Dec 9, 2015 · 5 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries

Comments

@daschl
Copy link

daschl commented Dec 9, 2015

Hi folks,

mainly tested on 1.4.0, but I also tested nightly.

this may be a compiler bug, but I'm not sure. So here is what I know is going on. I have the following code which was generated by crabtw/bindgen and is intended to work over a union in a c library (part of the relevant code to not make it too noisy):

#[repr(C)]
struct TopologyObjectAttributes {
    _bindgen_data_: [u64; 5usize],
}

impl TopologyObjectAttributes {
    pub unsafe fn cache(&mut self) -> *mut TopologyObjectCacheAttributes {
        let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
        ::std::mem::transmute(raw.offset(0))
    }
    pub unsafe fn group(&mut self) -> *mut TopologyObjectGroupAttributes {
        let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
        ::std::mem::transmute(raw.offset(0))
    }
    pub unsafe fn pcidev(&mut self) -> *mut TopologyObjectPCIDevAttributes {
        let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
        ::std::mem::transmute(raw.offset(0))
    }
    pub unsafe fn bridge(&mut self) -> *mut TopologyObjectBridgeAttributes {
        let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
        ::std::mem::transmute(raw.offset(0))
    }
    pub unsafe fn osdev(&mut self) -> *mut TopologyObjectOSDevAttributes {
        let raw: *mut u8 = ::std::mem::transmute(&self._bindgen_data_);
        ::std::mem::transmute(raw.offset(0))
    }
}

#[repr(C)]
pub struct TopologyObjectCacheAttributes {
    pub size: c_ulonglong,
    pub depth: c_uint,
    pub linesize: c_uint,
    pub associativity: c_int,
    pub _type: TopologyObjectCacheType,
}

impl TopologyObjectCacheAttributes {
    pub fn size(&self) -> u64 {
        self.size
    }

    pub fn depth(&self) -> u32 {
        self.depth
    }
}

I'm showing only the impl for the cache part, but the other union variants work exactly the same way. The struct fields are public in the cache one for testing purposes, of course ideally I only have the getters. Now I have some code which does its unsafe job to dereference the pointers and ultimately get to the members of the struct.

    pub fn cache_attributes(&self) -> Option<&TopologyObjectCacheAttributes> {
        let cache_ptr = unsafe { (*self.attr).cache() };
        if cache_ptr.is_null() {
            None
        } else {
            unsafe { Some(&*cache_ptr) }
        }
    }

This is called like:

p.cache_attributes().unwrap().size();

Now here comes the important stuff. When I call it like this, the compiler fails on linking:

note: ld: warning: directory not found for option '-L/Users/michael/rust/hwloc-rs/.rust/lib/x86_64-apple-darwin'
ld: warning: directory not found for option '-L/Users/michael/rust/hwloc-rs/lib/x86_64-apple-darwin'
Undefined symbols for architecture x86_64:
  "topology_object::TopologyObjectCacheAttributes::size::h5726f74039bc15c7uMa", referenced from:
      main::hf733474fad67530eiaa in processor_cache.0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

But when I change it to direct struct member access (not going through the getter) it works! So this compiles fine and runs as expected in my test code:

p.cache_attributes().unwrap().size;

I'm not an expert in rust so I have a hard time providing a smaller test case. If someone wants to run the code you can clone the repo and run the example (https://github.com/daschl/hwloc-rs/blob/master/examples/processor_cache.rs#L20) - $ cargo run --example processor_cache.

Just make sure to have the hwloc library installed (1.11.1, from here https://www.open-mpi.org/software/hwloc/v1.11/), just plain configure, make, sudo make install.

@sfackler sfackler added the A-linkage Area: linking into static, shared libraries and binaries label Dec 9, 2015
@petrochenkov
Copy link
Contributor

Are struct TopologyObjectCacheAttributes and fn size public enough in the original not reduced code?
By "public enough" here I mean "can be named from other crates".
If they are defined in some private inner module and can't be named from other crates, then it may be a duplicate of #16734

@petrochenkov
Copy link
Contributor

Ah, I see, the full code is available in https://github.com/daschl/hwloc-rs
It is indeed the same problem as in #16734
Try to insert pub use topology_object::TopologyObjectCacheAttributes; into src/lib.rs, the problem should go away.

@alexcrichton
Copy link
Member

yeah I agree this is a dupe of #16734, so closing in favor of that. Thanks for the report though!

@daschl
Copy link
Author

daschl commented Dec 9, 2015

Thanks for the quick triage! Good to know the issue is being worked on - it's a little confusing right now :)

@daschl
Copy link
Author

daschl commented Dec 10, 2015

@petrochenkov indeed, this fixed the issue. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries
Projects
None yet
Development

No branches or pull requests

4 participants