0

I built a SoC written in Verilog, compiled the c code into a binary file and initialized the SoC ROM with it. In order to design an error injection, I needed to be able to artificially specify the ROM address after the assembly of an instruction such as printf ("123"). Is there a way to do this, for example, using inline assembly?

KabiLink
  • 61
  • 5
  • 2
    `printf("123")` can't compile to a single instruction. Do you want the address for each instruction involved in setting up the arg to pass, or the `call printf` or equivalent? In a debug build those will be contiguous, otherwise they might not be. – Peter Cordes Jun 07 '23 at 17:27
  • 2
    You might possibly be able to get a linker to place your whole program so one label lands at a certain address, e.g. `. = 0x10000 - (symbol - start_of_text)` in a linker script or something like that. And you can put individual functions in their own section so you can play with layout in the linker (`gcc -ffunction-sections`) so you could do that on a per-function basis. Using inline asm to emit a label like `asm("label1:" ::: "memory");` might happen to work in a debug build only, depending on what you want. – Peter Cordes Jun 07 '23 at 17:29
  • I want the block of instructions in printf("123") to be specified, I'll try linker。 How can I select your respond as answer? @Peter Cordes – KabiLink Jun 08 '23 at 13:36
  • I'm not 100% certain if this is what you want... but you could do what other processors do for interrupts. they make a table in ram/rom and fill it with pointers to error handler functions and such. You could probably do something similar. Then use peter's trick to align that table at a certain address. Pros: It is unimportant if the functions are contiguous or move. Con: The items in the table are pointers, so there is a load and then a jump instead of just a direct jump. (the few cycles for this may not matter on your SoC though) – Watachiaieto Jun 08 '23 at 15:04

1 Answers1

0

There might be a very hacky and unreliable way that happens to work in a debug build, relying on assumptions about how compilers work. IDK why you'd want to do it; you can't jump there from outside the function. If you just want to be able to set a breakpoint, normally you can do that by line number with debug info.


Creating an asm label / symbol-table entry

printf("123") can't compile to a single instruction. There will be some that set up a pointer arg, and one or more that actually do a call printf or equivalent. In a debug build those will be contiguous block, otherwise they might not be.

In a debug build (optimization disabled), if you use inline asm to emit a label in the middle of your C function, like asm(".globl foo; foo:" ::: "memory"), it will probably be right before the block of instructions corresponding to the next C statement. (In an optimized build, the instructions corresponding to one C statement won't be in a contiguous block, and there'd be no way to do anything like what you're asking, except maybe with C goto labels like foo: and using GNU C labels-as-values to take their address. But I don't think you could control their address with the linker since you wouldn't know an asm symbol name.)


Using a linker script to move the start of a section so your symbol lands at the desired address

You can use a linker script to place the start of the .text section at a certain address. Something like . = 0x401000 before emitting the segment that maps the sections you want.

If you compute that address like . = 0x401000 - (symbol - start_of_text), using the distance of the symbol from the start of the section, then the symbol should end up at the address you want.

You can put individual functions in their own section so you can play with layout in the linker (gcc -ffunction-sections) so you could do that on a per-function basis.


I wouldn't recommend doing this. If something you're designing relies on this to work correctly, design it differently. This is horrible.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847