the code:
#include <gb/gb.h>
#include <stdio.h>
union long_ptr {
long ptr;
struct {
void * ofs;
int seg;
} segofs;
};
long to_longptr(void* ptr, int bank) {
static union long_ptr tmp = {.segofs = {ptr, bank}};
return tmp.ptr;
}
long tmp;
void main() {
tmp = to_longptr(&to_longptr, 1);
printf("%x %x\n", (int)tmp, (int)(tmp >> 16));
}
the result:
.area _GSINIT
;test.c:13: static union long_ptr tmp = {.segofs = {ptr, bank}};
ld de, #_to_longptr_tmp_65536_64
ldhl sp, #2
ld a, (hl)
ld (de), a
inc de
inc hl
ld a, (hl)
ld (de), a
ld de, #(_to_longptr_tmp_65536_64 + 0x0002)
inc hl
ld a, (hl)
ld (de), a
inc de
inc hl
ld a, (hl)
ld (de), a
;--------------------------------------------------------
; Home
;--------------------------------------------------------
.area _HOME
.area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
.area _CODE
;test.c:12: long to_longptr(void* ptr, int bank) {
; ---------------------------------
; Function to_longptr
; ---------------------------------
_to_longptr::
add sp, #-4
;test.c:14: return tmp.ptr;
ld de, #_to_longptr_tmp_65536_64 + 0
ld a,(de)
ldhl sp, #0
ld (hl+), a
inc de
ld a, (de)
ld (hl+), a
inc de
ld a, (de)
ld (hl+), a
inc de
ld a, (de)
ld (hl), a
pop de
push de
dec hl
ld a, (hl+)
ld h, (hl)
ld l, a
;test.c:15: }
add sp, #4
ret
function code is torn into 2 pieces
commandline:
sdcc -mgbz80 --no-std-crt0 -I ..\..\gbdk\include -I ..\..\gbdk\include\asm -I src\include -c test.c -o build\test.rel
version:
SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ez80_z80/z80n/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15 4.0.2 #11619 (MINGW64)
published under GNU General Public License (GPL)
workaround is this:
the asm result is this:
ps: but shouldn't it return the values loaded from the static struct? why copying to local variable?
Last edit: Tony Pavlov 2020-05-24
maybe it is not clear what is wrong here. the initialization of a local static variable in my example depends on the parameters, that are passed into the function. when the initialization of tmp is moved to _GSINIT area, there can't be parameters of a function on the stack. so this "ldhl sp, #2" is completely wrong. the initialization of tmp may be moved to _GSINIT only if the whole initialization is constant.
ps: static is better here because faster code is generated for that on gbz80 target (compared with the stack-allocated struct).
What is wrong here is a missing diagnostic:
SDCC should report
instead of trying to generate some code. Interestingly, the problem seems to be related to union / struct: For a plain int, we get the expected error.
P.S.: From the C standard (C2X draft N2479): "All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals."