https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69221
Bug ID: 69221 Summary: gcc on m68k miscompiles function type casts Product: gcc Version: 5.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: slyfox at inbox dot ru Target Milestone: --- Created attachment 37298 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=37298&action=edit sample with broken ABI This came up as a miscompilation of GHC: https://ghc.haskell.org/trac/ghc/ticket/11395 Consider the following small snippet: /* needed to introduce a symbol */ extern void* f(); /* real prototype is 'int f(void);' */ int g(void) { /* cast a symbol to known function type, returns 'int' */ return 1 + ((int (*)(void))f)(); } /* somewhere in other translation unit */ int __f (void) { return 42; } /* just for comparison */ void * __vf (void) { return (void*)42; } $ m68k-unknown-linux-gnu-gcc -O2 -S demo1.c -fomit-frame-pointer [ Also issues a warning: warning: function called through a non-compatible type return 1 + ((int (*)(void))f)(); ^ ] generates the following assembly: g: jsr f move.l %a0,%d0 ; 'g' kills register 'd0', resould of called would-be 'f' addq.l #1,%d0 rts __f: moveq #42,%d0 rts __vf: move.w #42,%a0 moveq #42,%d0 rts The idea here is extern void* f(); line brings a .text symbol of yet unknown propotype. Later *at .c file generation time) we get information about symbol 'f' and cast it to known type: ((int (*)(void))f)(); But caller does not expect result to present in 'd0' data register, expects 'a0' address register. [a note: GHC used to introduce unknown symbols in scope as extern void* f(void); but that broke on PPC64 ELFv2 and we changed to less precise extern void* f(); ] Looks like GCC bug to ignore actual 'int (*)(void)' ABI of a symbol at call site.