rust-console/gba

question about arm7 binaries on debug

SeleDreams opened this issue · 17 comments

Hi, sorry for the slightly unrelated question but i was having an issue with arm7 binaries on my port of rust to DS in debug mode and i was wondering if you had any idea about why t happens

the arm7 binaries i build for DS do work in release mode without much issues but when in debug mode they end up having issues
someone who looked at the generated elf in depth told me "it jumps to random memory but no debugger works well enough to understand why"

I'm wondering if it might be due to an error in my json describing the thumbv4t target ? https://github.com/SeleDreams/libnds-rs/blob/master/thumbv4t-nintendo-ds.json

I did try with an empty main function and it resulted in the same issue so I doubt it comes from the code itself

Well, your target description seems approximately similar to the thumbv4t-none-eabi built into the compiler.

Can you post the binary of the minimal program with a debug build? It should be small enough that we can look at it with objdump and try to puzzle out why it's doing what it's doing.

At least, I hope. On the GBA a "minimal" program comes out to a few hundred instructions at most, so I don't expect a minimal DS program for the arm7 to be too much bigger than that.

fifo_example.zip
this is the arm7 elf

i think it might be caused by the gdb_script section of 22 bytes that gets inserted before the init_array sections, but i dunno what i could do about that

I use my own linker script for the GBA, so you could maybe do that.

checks the ELF file

holy heck it's 197k, that's... way huge.

So I dumped it with this

arm-none-eabi-objdump --headers --disassemble --demangle --architecture=armv4t --no-show-raw-insn -Mreg-names-std fifo_example.arm7_elf >tmp.txt

And got a file: fifo_example.arm7_elf.dump.txt

I'm deeply concerned at how often there's "undefined instruction" in the output. Are you sure that the linker script and CRT0 and all that is intended to be used with the v4t CPU? Because if there's v5te code mixed in trying to run on the v4t CPU then that'd cause huge problems.

It actually was compiled as thumbv4t, which might be the reason.
I was able to fix my issue however by setting in the target settings
"emit-debug-gdb-scripts": false,

also when it comes to linker script and crt0, I am litterally using the ds_arm7.spec from devkitpro so it normally should be fine.

output.txt
I checked the new output with my fixed script and it looks way better

there are no undefined instructions at all anymore

edit : actually seems like it's building with compiler optimisations of level 3 that cause these undefined instructions. building with level 1 optimisation generates the clean output file you saw

And the source code is all in a high level language (C/C++/Rust/whatever), not just handwritten assembly? I normally have the gba crate to use opt-level=3 and i've never seen undefined instructions except in padding portions of the code (eg: padding between a function's instructions and its literal data)

And the source code is all in a high level language (C/C++/Rust/whatever), not just handwritten assembly? I normally have the gba crate to use opt-level=3 and i've never seen undefined instructions except in padding portions of the code (eg: padding between a function's instructions and its literal data)

the .spec file just makes the program link the ld and the crt
the source of devkitpro's crt0 is here
https://github.com/devkitPro/devkitarm-crtls/blob/master/ds_arm7_crt0.s
and the linker script is here https://github.com/devkitPro/devkitarm-crtls/blob/master/ds_arm7.ld

tbf, it's still pretty unstable in fact, there are times where it will still end up generating broken code depending on the debug settings set

yeah that CRT0 code looks totally fine at a glance.

I'm really baffled that it got turned into so much stuff that the disassembler called undefined, particularly because of optimization level, which should only affect higher level code.

I think what might generate all this code is the fact it includes a lot of bindings for the entire libnds API, so not all of this code is getting run, but it has a lot of functions defined

like, bindgen technically even made wrappers for the std c library. i don't have control over it i think

I'd try to start from a fresh linker script that does at little as possible, and then a source code base that's also as small as possible, then build something that can "avoid crashing", and expand out from there.

Probably, long term, you don't even want all that C code in there anyway. I'm just guessing, but at least on the GBA, there's nothing that the various C libraries offer that can't be quickly replaced in pure rust. I think the DS is probably pretty similar, where it's a small enough platform that you can "write all the code yourself", given a little time.

the issue is that it would be quite a lot of work to reimplement everything from scratch. even more since i don't have experience with that low level programming. the lowest i tend to go is with using graphics APIs. not directly communicating with registers and co

it would take me months, maybe even years to learn this stuff, meanwhile my goal was to make a cross platform rust game engine working on DS. that's why it takes priority to me to get it working

also I found out the exact cause of undefined instructions, it wasn't the optimisation level, it was caused by
strip = true

Mmmm, improper stripping could totally mess up the bytes and make a bunch of stuff undefined, yeah.

But also, learning the low level initialization wouldn't take years! I started the GBA crate with no background knowledge at all.

I was more referring to interfacing with the hardware directly with no API. it takes time to learn and make an entire API around a low level system.
at least at the moment i find it more productive to use an existing API