0

Background

I am running the qemu-arm user space emulator inside of a Docker container on Docker for Mac.

I am working on a code base that runs on cortex-m4 processors. I want to be able to cross-compile the code in the docker container to target the cortex-m4 processor and run that code on the qemu-arm user space emulator.

to test this, I have a simple C program (/tmp/program.c):

int main() {
    return 0;
}

I use the debian:stable docker image as a base.

I compile the program with the GNU arm toolchain like so:

arm-none-eabi-gcc -mcpu=cortex-m4 --specs=nosys.specs /tmp/program.c

Then I attempt to run this with qemu-arm in the docker container:

qemu-arm -cpu cortex-m4 -strace ./a.out

But I get the following error:

--- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x0007fff0} ---
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault

From what I understand, SIGSEGV occurs in a few scenarios, the only one that makes sense here is that I am accessing memory that I don't have access to when I attempt to run the binary in the qemu-arm user space.

It would seem that the si_addr=0x0007fff0 is the address that I am accessing that I am not supposed to.

Since my program does very little, I am assuming this inaccessible address might be where qemu-arm is attempting to store the binary to run? But I don't see an option in qemu-arm to specify this.

Questions

So my questions are:

  • how can I verify what is attempting to access that inaccessible address?
  • if I am correct in my thinking (that this is where qemu-arm is attempting to store the binary to be run), is there a way to change that? I didn't see one in any of the command line options

More information

Docker version 20.10.6, build 370c289

Dockerfile to reproduce:

FROM debian:stable

RUN apt-get update
RUN apt-get install -y gcc-arm-none-eabi qemu-user gcc

RUN echo 'int main() {return 0;}' > /tmp/program.c

# running the program on the docker container exits successfully
RUN gcc /tmp/program.c
RUN ./a.out

# running the program in `qemu-arm` errors
RUN arm-none-eabi-gcc -mcpu=cortex-m4 --specs=nosys.specs /tmp/program.c
RUN qemu-arm -cpu cortex-m4 -strace ./a.out
northsideknight
  • 1,519
  • 1
  • 15
  • 24

1 Answers1

1

qemu-arm is an emulator for Linux user-space binaries. The program you're compiling seems to be built with a bare-metal toolchain. It's not impossible to compile a bare-metal binary in such a way that it will run as a Linux user-space program as well, but you have to take specific steps to make it work that way.

You should probably think about whether what you really wanted was:

  • build a Linux binary targeting Cortex-M4, and run it on qemu-arm
  • build a bare-metal binary, and run it on qemu-system-arm
  • something else

For example, how are you expecting your program to produce output? Is the program going to want to talk directly to (emulated) hardware like a serial port, or to other devices? Does the program need to run interrupt handlers?

The best way to debug what's happening is to get QEMU to start its gdbstub, and connect an arm-aware gdb to it. Then you can single step through. (This will probably be a confusing introduction to your toolchain's C runtime startup code...)

Peter Maydell
  • 9,707
  • 1
  • 19
  • 25
  • hey thanks for the reply @Peter Maydell, for some context: I am adding unit testing to a embedded software project that historically has none so that we can run it in CI. My goal is to get this to run as close to how it does on the actual hardware device as possible. So, what I want to test at this moment is functionality that doesn't interact with hardware, but should be able to compile and run on Cortex-M4. So it sounds like the second option you mentioned "build a bare-metal binary, and run it on qemu-system-arm" is what I want to be doing. – northsideknight Sep 14 '21 at 18:21