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

Some functions fail to produce Rust output or even pick up the right function #121

Open
therealprof opened this issue Jun 6, 2019 · 12 comments

Comments

@therealprof
Copy link
Contributor

I haven't quite figured out what triggers the erratic behaviour but for some functions I'd get something like:

# cargo asm --rust core::ptr::real_drop_in_place
 bx      lr
_ZN8cortex_m10peripheral3dcb43_$LT$impl$u20$cortex_m..peripheral..DCB$GT$12enable_trace17hda6f0a10537b914cE:
 movs    r0, #1
 lsls    r0, r0, #24
 ldr     r1, .LCPI4_0
 ldr     r2, [r1]
 orrs    r2, r0
 str     r2, [r1]
 bx      lr
.LCPI4_0:
_ZN8cortex_m10peripheral3dcb43_$LT$impl$u20$cortex_m..peripheral..DCB$GT$13disable_trace17h420bb4cd508eaa5aE:
 movs    r0, #1
 lsls    r0, r0, #24
 ldr     r1, .LCPI5_0
 ldr     r2, [r1]
 bics    r2, r0
 str     r2, [r1]
 bx      lr
...

or

# cargo asm --rust "<&mut W as core::fmt::Write>::write_char"
 push    {r4, r5, r6, r7, lr}
 sub     sp, #20
 ldr     r0, [r0]
 movs    r6, #0
 str     r6, [sp, #4]
 cmp     r1, #127
 bhi     .LBB1_2
 add     r2, sp, #4
 strb    r1, [r2]
 movs    r4, #1
 b       .LBB1_7
...
.LBB4_8:
 movs    r1, #1
 mov     r0, r1
 add     sp, #20
 pop     {r4, r5, r6, r7, pc}
_ZN20cortex_m_semihosting5debug4exit17h4949d2566b7458ddE:
 push    {r7, lr}
 ldr     r1, .LCPI5_0
 cmp     r0, #0
 bne     .LBB5_2
 adds    r1, r1, #3
.LBB5_2:
 movs    r0, #24
 bl      __syscall
 pop     {r7, pc}
.LCPI5_0:
_ZN20cortex_m_semihosting5debug16report_exception17hef5e5f51f27bb33eE:

In both cases cargo-asm seems to have picked up the incorrect function and to demangle the symbols.

@gnzlbg
Copy link
Owner

gnzlbg commented Jun 6, 2019

Did Rust mangling scheme change already? I recall there being an RFC about this. Maybe upgrading rustc_demangle fixes this, but I'm not sure.

@therealprof
Copy link
Contributor Author

No, this is with stable: rustc 1.35.0 (3c235d560 2019-05-20)

There's now support for a new mangling scheme in nightly but it's also not turned on by default yet.

@therealprof
Copy link
Contributor Author

NB: It works in a lot of of cases and fails in a lot of other cases within the same crate with the same tooling.

e.g.:

# cargo asm --rust core::result::unwrap_failed
 fn unwrap_failed<E: fmt::Debug>(msg: &str, error: E) -> ! {
 sub     sp, #56
 movs    r0, #16
 str     r0, [sp, #8]
 ldr     r0, .LCPI5_0
 str     r0, [sp, #4]
 panic!("{}: {:?}", msg, error)
 ldr     r0, .LCPI5_1
 str     r0, [sp, #48]
 add     r0, sp, #52
 str     r0, [sp, #44]
 ldr     r0, .LCPI5_2
 str     r0, [sp, #40]
 add     r0, sp, #4
 str     r0, [sp, #36]
 movs    r0, #2
     Arguments { (libcore/fmt/mod.rs:316)
     str     r0, [sp, #32]
     add     r1, sp, #36
     str     r1, [sp, #28]
     movs    r1, #0
     str     r1, [sp, #24]
     str     r1, [sp, #20]
     str     r0, [sp, #16]
     ldr     r0, .LCPI5_3
     str     r0, [sp, #12]
     add     r0, sp, #12
     $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), (libcore/macros.rs:18)
     ldr     r1, .LCPI5_4
     bl      _ZN4core9panicking9panic_fmt17h0d6d5c8b201e3246E
.LCPI5_0:
.LCPI5_1:
.LCPI5_2:
.LCPI5_3:
.LCPI5_4:

@gnzlbg
Copy link
Owner

gnzlbg commented Jun 6, 2019

You might want to inspect the real assembly generated by rustc (and not the one reported by cargo asm), and see if something is fishy (I think rustc's assembly output is a "best effort").

Right now it is not possible to pass cargo asm an assembly text file, and ask it to find some function in that file, but it shouldn't be hard to extend cargo asm with a --from-file=foo.asm option. That could allow better testing the tool, by providing assembly snippets via the CLI, and verifying the option. The tests we currently have are end-to-end integration tests, and because the toolchain changes all the time, they are quite brittle.

@therealprof
Copy link
Contributor Author

Ooh. I think we have something here... There're three core::ptr::real_drop_in_place functions in the final linked binary:

080017b8 <core::ptr::real_drop_in_place>:
 80017b8:       4770            bx      lr
 80017ba:       d4d4            bmi.n   8001766 <<cdc_acm::SerialPort<B> as usb_device::class::UsbClass<B>>::get_configuration_descriptors+0x13a>
0800339a <core::ptr::real_drop_in_place>:
 800339a:       4770            bx      lr
08003fee <core::ptr::real_drop_in_place>:
 8003fee:       4770            bx      lr

The write_char function from above looks completely different, though:

08003ff0 <<&mut W as core::fmt::Write>::write_char>:
 8003ff0:       b510            push    {r4, lr}
 8003ff2:       b082            sub     sp, #8
 8003ff4:       6800            ldr     r0, [r0, #0]
 8003ff6:       2200            movs    r2, #0
 8003ff8:       9201            str     r2, [sp, #4]
 8003ffa:       297f            cmp     r1, #127        ; 0x7f
 8003ffc:       d807            bhi.n   800400e <<&mut W as core::fmt::Write>::write_char+0x1e>
 8003ffe:       aa01            add     r2, sp, #4
 8004000:       7011            strb    r1, [r2, #0]
 8004002:       2201            movs    r2, #1
 8004004:       a901            add     r1, sp, #4
 8004006:       f7ff ffa9       bl      8003f5c <<cortex_m_semihosting::hio::HStderr as core::fmt::Write>::write_str>
 800400a:       b002            add     sp, #8
 800400c:       bd10            pop     {r4, pc}
 800400e:       0aca            lsrs    r2, r1, #11
 8004010:       d10e            bne.n   8004030 <<&mut W as core::fmt::Write>::write_char+0x40>
...

Funny enough I've a few slightly differing unwrap_failed functions, too but they seem close enough to the cargo-asm output.

@gnzlbg
Copy link
Owner

gnzlbg commented Jun 6, 2019

FWIW, cargo-asm doesn't really inspect the final binary. rustc generates LLVM-IR, which is then optimized, but we tell LLVM that instead of generating a binary from that LLVM-IR, they should translate it to "textual assembly" instead. I've always been a bit skeptic about how good that "textual assembly" matches the machine code that is actually generated.

The reason we do it this way is that LLVM actually has support for embedding comments in the textual assembly generated, and we wanted to show those too, but rustc doesn't really support that very good right now. The alternative here would be to compile the binary normally, and then disassemble it, and try to look for the function symbols there. Sometimes I wish I would have gone this way.

@therealprof
Copy link
Contributor Author

Not so sure disassembling the final binary is a good approach. Even with "debug info" in the final release binary the information level is really lacking which is one of the reasons I care so much about cargo-asm. 😅

@gnzlbg
Copy link
Owner

gnzlbg commented Jun 6, 2019

Yeah, i'm not sure either. More than about the quality of the assembly displayed, I thought it might be an interesting approach to explore to produce something more faithful to what's executed, and also for speed. Compiling and linking a binary, and then doing a disassembly, is for whatever reason much faster than dumping the textual assembly through LLVM.

@AaronKutch
Copy link

AaronKutch commented Jun 25, 2019

This issue is constantly getting in my way. I just encountered a function in a library that I cannot seem to get the assembly for, even when wrapping it in a inline(never) function in a binary. It either gives me code from the main function or does not find it at all.
edit: I remembered to add pub to the function and added inline(always) directly on the function in the library, but trying to chain functions and permutating inline(never) and inline(always) is still giving me the wrong function output

@gnzlbg
Copy link
Owner

gnzlbg commented Jun 25, 2019

even when wrapping it in a inline(never) function in a binary.

I suppose you are then searching for that inline(never) function, that this function is pub, and that this function is not generic, right?

@AaronKutch
Copy link

AaronKutch commented Jun 25, 2019

I managed to get a reproduction for the stable channel. I am trying to get the assembly from my specialized-div-rem crate of the u128_div_rem function. It has #[inline] applied to it because only one element of the tuple it returns is used sometimes, so I want to be able to see what the inlining does. Sometimes though, the function inlines further than I want, or cargo asm is acting up and showing the wrong functions even if no inlining is occuring. Usually, I am able to hack around problems like this without having the clone the library and modify it, by doing this:
in Cargo.toml,

...
[dependencies]
specialized-div-rem = "0.0.4"
rand = "0.6.5"

in main.rs,

#[inline(never)]
pub fn fun(lkj0: u128, lkj1: u128) -> (u128, u128) {
    specialized_div_rem::u128_div_rem(lkj0, lkj1)
}

fn main() {
    let lkj0 = 7325176125387951268757865215152512u128;
    let lkj1 = 112879451768156781546789154876156715u128;
    dbg!(fun(lkj0, lkj1));
}

and running cargo asm [name of binary]::fun. However, it results in assembly from the wrong function. I can fix it by cloning the library and changing the function to use inline(never) on the library side, but this is far from convenient or practically impossible if I need to do it when using something that binds to a C++ library. Also, I should mention that I have never once seen --rust do anything in all my time with cargo asm.

Another problem I have is that cargo asm [incomplete path] sometimes does not show a helpful list of potential functions. The master branch of the apint crate currently has impls spread across several modules, so I need to run stuff like cargo asm "apint::apint::data::morestuff::<impl bunch of nontrivial mangling stuff that I cannot figure out without cargo asm mentioning it>::wrapping_add_assign". On some libraries like my specialized-div-rem library, cargo asm never shows the helpful list, so I may be unable to actually find the function. If it is possible, I would recommend that functions are addressed just how they would be addressed in Rust code, e.g. cargo asm apint::ApInt::wrapping_add_assign.

@AaronKutch
Copy link

AaronKutch commented Jun 25, 2019

It seems to me that cargo-asm is something that belongs in the nightly Rust compiler itself. I understand that cargo-asm relying on optimized compiler output is always going to need fragile hacks if it were able to be "ergonomic". Either way, I suppose we are all waiting on stabilized mangling and internal compiler refactors.

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

3 participants