Am 07.12.24 um 02:03 schrieb Oleg Endo:
On Fri, 2024-12-06 at 16:51 +0100, Georg-Johann Lay wrote:
The CRC tables ARE put into .rodata, not into .data.
The correct question is: Why is avr putting .rodata into RAM?
Suppose the following C code:
char read_c (const char *p)
{
return p[1];
}
Where p may point to .rodata, .data, .bss etc.
Now suppose .rodata is located in flash and .data and .bss
are located in RAM.
Thanks for the detailed explanation!
I feel you. I've been coding on mcs51 MCUs for a couple of years now (on
SDCC, meh)
This would imply that there is some means to tell apart
different address spaces by looking at p. This is *not* the
case. In particular, flash address 0x4 looks exactly the same
like RAM address 0x4. Both are 16-bit address 0x0004, and there
is no way to tell them apart.
I'm a little surprised that there's no way to get pointer/symbol meta-
information from within the backend code to identify data being accessed
that will end up in __code / __flash / .rodata / .text.
There is a way: Named address spaces as of ISO/IEC DTR 18037.
Depending on the address space, different instructions, different
address register(s), different addressing modes have to be used.
You cannot just put an object into a different address space
without adjusting *all* accesses: Their instructions, their
address registers, their addressing modes, you name it.
In some cases it's even required so set some SFR to the MSByte
of a 24-byte address since GPRs can only hold 16-bit addresses.
So the question is. Who is specifying which address space to use?
Two ways:
1) The user knows that some object may live in a specific AS.
All accesses to the object must use a pointer qualified for
that AS (or otherwise, the code won't work).
2) The compiler assigns an AS (with the help of a target hook).
All decls / rtxes thet accesses the object must have the
correct TYPE_ADDR_SPACE / MEM_ADDR_SPACE qualification,
or else wrong code is generated.
Notice that a "const" qualifier is not enough to conclude that
data is located in .rodata. For example, in
char read_c (const char *pc)
{
return pc[1];
}
it is perfectly fine to pass a pointer to .data / volatile memory.
Hence the code must work for addresses in .data as well as in .rodata.
On SDCC/mcs51 things are simple enough so that we can at least try to lookup
a given symbol from the backend code and see if it's got a known address
space assigned to it (via (forward) declaration). This can be used to
optimize accesses to e.g. SFRs even during later stages of compilation.
AVR does that, too. SFRs are located in a specific address range
(of the generic address space). There are also attributes to
specify that specific instructions /may/ be used to access an SFR,
though that's rather an optimization. SFRs on AVR are such that
they don't require new ASes.
Johann
Best regards,
Oleg Endo