z88dk / z88dk

The development kit for over a hundred z80 family machines - c compiler, assembler, linker, libraries.
https://www.z88dk.org
Other
913 stars 173 forks source link

zsdcc: bug in static initializer for unions in structs #898

Open aralbrec opened 6 years ago

aralbrec commented 6 years ago

I'll just copy this out of #894 :

I'm amazed but it looks like zsdcc does named initilaization:

#include <stdint.h>

struct esx_drvapi
{
   union
   {
      uint16_t bc;
      struct
      {
         uint8_t driver;
         uint8_t function;
      }
      call;
   };

   uint16_t de;
   uint16_t hl;
};

//struct esx_drvapi rtc = { {0}, 0, 0 };   // sdcc incorrectly initializing c89 way too
struct esx_drvapi ruc = { .call.driver = 1, .call.function = 2, .de = 3, .hl = 4 };

zcc +zxn -a -clib=sdcc_iy zzz.c

but it's getting the union wrong and doing both members of the union in the data structure:

_ruc:
    DEFW +0x0000
    DEFB +0x01
    DEFB +0x02
    DEFW +0x0003
    DEFW +0x0004

So .bc and the .call struct are not sharing space. That's why the weird initilaizer was working - the struct layout is broken.

So I think the only way to do it right for both compilers is to define the struct in asm.

In c make the compiler aware of it:

extern struct esx_drvapi ruc;

In a separate asm file define ruc's contents. Notice a data section is used because this will be non-zero initialized.

asm

SECTION data_user

PUBLIC _ruc

_ruc:

   defb 0   ; .call.driver
   defb 0   ; .call.function
   defw 0   ; .de
   defw 0   ; .hl

Then add that asm file to the compile line.

aralbrec commented 6 years ago

Thankfully it looks like the code generator gets it right so it's just the initialization broken in sdcc:

#include <stdint.h>

struct esx_drvapi
{
   union
   {
      uint16_t bc;
      struct
      {
         uint8_t driver;
         uint8_t function;
      }
      call;
   };

   uint16_t de;
   uint16_t hl;
};

//struct esx_drvapi rtc = { {0}, 0, 0 };
struct esx_drvapi ruc = { .call.driver = 1, .call.function = 2, .de = 3, .hl = 4 };

void main(void)
{
    ruc.bc = 10;
    ruc.de = 12;
    ruc.hl = 15;
    ruc.call.driver = 1;
    ruc.call.function = 2;
}
_main:
    ld  hl,0x000a
    ld  (_ruc), hl
    ld  l,0x0c
    ld  ((_ruc + 0x0002)), hl
    ld  l,0x0f
    ld  ((_ruc + 0x0004)), hl
    ld  hl,_ruc
    ld  (hl),0x01
    ld  hl, +(_ruc + 0x0001)
    ld  (hl),0x02
    ret
aralbrec commented 6 years ago

Will have to check if this is addressed in later sdcc versions.

spth commented 6 years ago

I just did some testing with current SDCC 3.7.2 #10539; there is indeed a problem when using designated initializers with anonymous unions; it seems it results in an error message, not a silent failure though. I filed https://sourceforge.net/p/sdcc/bugs/2810/

Philipp

suborb commented 4 years ago

On r11715 this now reports:

init.c:21: warning 147: excess elements in scalar initializer after 'ruc'
init.c:22: error 47: indirections to different types assignment
Caught signal 11: SIGSEGV
feilipu commented 4 years ago
// sdcc -S bug2810.c 

struct s
{
   union
   {
      int a;
      int b;
   };

   int c;
   int d;
};

struct s s2 = { .a = 0, .c = 3, .d = 4 };
feilipu commented 3 years ago

Still open as of r12402.

suborb commented 1 year ago

r14110 now reports this:

named.c:21: warning 147: excess elements in scalar initializer after 'ruc'
named.c:22: error 47: indirections to different types assignment
Internal error: validateLink failed in SPEC_NOUN(type) @ SDCCsymt.c:3950: expected SPECIFIER, got UNKNOWN
suborb commented 1 year ago

When I added named specifiers to sccz80 this case wasn't considered at all, so there we have:

named.c:21:32: fatal error: Unknown structure member call
Compilation aborted