Welcome, Guest. Please login or register.

Author Topic: GCC 3.4.0 error: asm-specifier for variable ... conflicts with asm clobber list  (Read 3057 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Hello, all. I'm building a library out of some code I'm porting to OS 3.x, and I've encountered an error that appears to be a product of changes made in GCC 3.3.x and higher. When referencing one of the library initialization functions in a global, I get errors like the following:

Code: [Select]

m68k-amigaos-gcc -v -m68020-60 -O2 -fomit-frame-pointer -c -I. libinit.c -fno-force-mem
Reading specs from /opt/gg/lib/gcc/m68k-amigaos/3.4.0/specs
Configured with: /opt/gg-src/gcc-3.4.0/configure --target=m68k-amigaos --prefix=/opt/gg --enable-languages=c --with-local-prefix=/opt/gg/m68k-amigaos --with-gnu-as --with-gnu-ld
Thread model: single
gcc version 3.4.0
 /opt/gg/libexec/gcc/m68k-amigaos/3.4.0/cc1.exe -quiet -v -I. -Dixemul -D__ixemul -D__ixemul__ libinit.c -quiet -dumpbase libinit.c -m68020-60 -auxbase libinit -O2 -version -fomit-frame-pointer -fno-force-mem -o /cygdrive/c/DOCUME~1/User/LOCALS~1/Temp/cc1KvfBo.s
ignoring nonexistent directory "/opt/gg/lib/gcc/m68k-amigaos/3.4.0/../../../../m68k-amigaos/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 .
 /opt/gg/lib/gcc/m68k-amigaos/3.4.0/include
 /opt/gg/lib/gcc/m68k-amigaos/3.4.0/../../../../m68k-amigaos/include
End of search list.
GNU C version 3.4.0 (m68k-amigaos)
 compiled by GNU C version 3.3.3 (cygwin special).
GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=130918
libinit.c: In function `LibInit':
libinit.c:13: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c:13: error: asm-specifier for variable `_n2' conflicts with asm clobber list
libinit.c:20: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c: In function `LibOpen':
libinit.c:26: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c:29: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c: In function `LibExpunge':
libinit.c:56: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c:58: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c:58: error: asm-specifier for variable `_n2' conflicts with asm clobber list
libinit.c: In function `LibClose':
libinit.c:37: error: asm-specifier for variable `_n1' conflicts with asm clobber list
libinit.c:39: error: asm-specifier for variable `_n1' conflicts with asm clobber list
make: *** [libinit.o] Error 1

(This is a Cygwin hosted build of GCC 3.4.0 with the last Geek Gadgets diffs.)

Take away the reference in the global, and the error goes away.

From what I can tell, it's actually an error in my code  that was brought on by a design "fix" starting with GCC 3.3.0.

Here's the source for the affected modules (BSD-style license, by the way):

libinit.h

Code: [Select]

#ifndef __LIBINIT_H__
#define __LIBINIT_H__

#include

#include
#include
#include
#include
#include

#include "my.library_rev.h"

char __aligned LibName[] = "my";
char __aligned LibIdString[] = VERSTAG;

struct MyBase
{
    struct Library         mb_Library;
    struct Segment *       mb_Segment;
    struct ExecBase *      mb_ExecBase;
    struct SignalSemaphore mb_Semaphore;
};

static struct MyBase * LibInit(struct MyBase * mb __asm("d0"), struct Segment * Segment __asm("a0"), struct ExecBase * ExecBase __asm("a6"));
static struct MyBase * LibOpen(struct MyBase * mb __asm("a6"));
static struct Segment * LibClose(struct MyBase * mb __asm("a6"));
static struct Segment * LibExpunge(struct MyBase * mb __asm("a6"));
static LONG LibExtFunc(VOID);

#endif /* __LIBINIT_H__ */

libinit.c

Code: [Select]

#include "libinit.h"

int main(void)
{
    return -1;
}

static struct MyBase * LibInit(struct MyBase * mb __asm("d0"), struct Segment * Segment __asm("a0"), struct ExecBase * ExecBase __asm("a6"))
{
    mb->mb_ExecBase = ExecBase;

    if ((mb->mb_ExecBase->AttnFlags & AFF_68020) == 0) {
        FreeMem((UBYTE *)mb - mb->mb_Library.lib_NegSize, mb->mb_Library.lib_NegSize + mb->mb_Library.lib_PosSize);
        return NULL;
    }

    mb->mb_Library.lib_Node.ln_Name = LibName;
    mb->mb_Library.lib_IdString = LibIdString;
    mb->mb_Segment = Segment;
    InitSemaphore(&mb->mb_Semaphore);
    return mb;
}

static struct MyBase * LibOpen(struct MyBase * mb __asm("a6"))
{
    ObtainSemaphore(&mb->mb_Semaphore);
    mb->mb_Library.lib_OpenCnt++;
    mb->mb_Library.lib_Flags &= ~LIBF_DELEXP;
    ReleaseSemaphore(&mb->mb_Semaphore);
    return mb;
}

static struct Segment * LibClose(struct MyBase * mb __asm("a6"))
{
    UWORD lib_OpenCnt = 0;

    ObtainSemaphore(&mb->mb_Semaphore);
    lib_OpenCnt = --mb->mb_Library.lib_OpenCnt;
    ReleaseSemaphore(&mb->mb_Semaphore);

    if (lib_OpenCnt == 0 && mb->mb_Library.lib_Flags & LIBF_DELEXP)
        return LibExpunge(mb);

    return NULL;
}

static struct Segment * LibExpunge(struct MyBase * mb __asm("a6"))
{
    struct Segment * Segment = NULL;

    if (mb->mb_Library.lib_OpenCnt != 0) {
        mb->mb_Library.lib_Flags |= LIBF_DELEXP;
        return NULL;
    }

    Remove((struct Node *)mb);
    Segment = mb->mb_Segment;
    FreeMem((UBYTE *)mb - mb->mb_Library.lib_NegSize, mb->mb_Library.lib_NegSize + mb->mb_Library.lib_PosSize);
    return Segment;
}

static LONG LibExtFunc(VOID)
{
    return 0;
}

const UWORD __aligned LibInitStruct[] = {
    INITBYTE(OFFSET(Node, ln_Type), NT_LIBRARY),
    INITBYTE(OFFSET(Library, lib_Flags), LIBF_SUMUSED | LIBF_CHANGED),
    INITWORD(OFFSET(Library, lib_Version), VERSION),
    INITWORD(OFFSET(Library, lib_Revision), REVISION),
    0
};

const APTR LibVectors[] = {
    LibOpen,
    LibClose,
    LibExpunge,
    LibExtFunc,
    (APTR)-1
};

const ULONG __aligned LibInitTable[] = {
    sizeof(struct MyBase),
    (ULONG)LibVectors,
    (ULONG)LibInitStruct,
    (ULONG)LibInit
};

const struct Resident LibRomTag = {
    RTC_MATCHWORD,
    (struct Resident *)&LibRomTag,
    (struct Resident *)&LibRomTag + 1,
    0,
    VERSION,
    NT_LIBRARY,
    0,
    LibName,
    LibIdString,
    LibInit
};

(Ugh. Mods: can we change the default font size for code blocks?)

Any ideas on how to get around the clobber error?

Trev
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Hmmm. As an example, in LibOpen, one of the functions I'm calling is ObtainSemaphore, which is called via this inline macro:

Code: [Select]

#define LP1NR(offs, name, t1, v1, r1, bt, bn) \
({ \
   t1 _##name##_v1 = (v1); \
   { \
      register struct Library *const _##name##_bn __asm(&quot;a6&quot;) = (struct Library*)(bn); \
      register t1 _n1 __asm(#r1) = _##name##_v1; \
      __asm volatile (&quot;jsr a6@(-&quot;#offs&quot;:W)&quot; \
      : /* no output */ \
      : &quot;r&quot; (_##name##_bn), &quot;rf&quot;(_n1) \
      : &quot;d0&quot;, &quot;d1&quot;, &quot;a0&quot;, &quot;a1&quot;, &quot;fp0&quot;, &quot;fp1&quot;, &quot;cc&quot;, &quot;memory&quot;); \
   } \
})

Anyone know which part of this is causing the clobber error?

I wish I had a bit more compiler mojo. . . .

Trev
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
@Trev

Try adding
Code: [Select]
#define ExecBase mb->mb_ExecBase before LibOpen.
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
That doesn't appear to do anything. None of the processed code (outside the code I've written) references ExecBase. There are some references to SysBase, but I think those are fine.

EDIT: I've tried compiling other "known good" code and get similar errors, so I'm guessing I've got issues with my inlines?

EDIT2: OK. I know how to make the error go away, but I don't know what else it might break (I need to read up on gcc's inline assembler). For example, ObtainSemaphore(&mb->mb_Semaphore) expands to this:

Code: [Select]

    (
        {
            struct SignalSemaphore * _ObtainSemaphore_v1 = (&mb->mb_Semaphore); {
                register struct Library *const _ObtainSemaphore_bn __asm(&quot;a6&quot;) = (struct Library*)(SysBase);
                register struct SignalSemaphore * _n1 __asm(&quot;a0&quot;) = _ObtainSemaphore_v1;
                __asm volatile (&quot;jsr a6@(-&quot;&quot;0x234&quot;&quot;:W)&quot; : : &quot;r&quot; (_ObtainSemaphore_bn), &quot;rf&quot;(_n1) : &quot;d0&quot;, &quot;d1&quot;, &quot;a0&quot;, &quot;a1&quot;, &quot;fp0&quot;, &quot;fp1&quot;, &quot;cc&quot;, &quot;memory&quot;);
            }
        }
    );


Notice how variable _n1 is stored in a0 (__asm("a0")). If you remove "a0" from the next line (I'm assuming this is the "clobber" list), the error goes away:

Code: [Select]

    (
        {
            struct SignalSemaphore * _ObtainSemaphore_v1 = (&mb->mb_Semaphore); {
                register struct Library *const _ObtainSemaphore_bn __asm("a6") = (struct Library*)(SysBase);
                register struct SignalSemaphore * _n1 __asm("a0") = _ObtainSemaphore_v1;
                __asm volatile ("jsr a6@(-""0x234"":W)" : : "r" (_ObtainSemaphore_bn), "rf"(_n1) : "d0", "d1", "a1", "fp0", "fp1", "cc", "memory");
            }
        }
    );


Any gcc inline assembler gurus out there? Should fd2inline be patched to fix this? Actually, an update to inline/macros.h should suffice. It looks like "d0", "d1", "a0", "a1", "fp0", "fp1", "cc", "memory" is the clobber list used throughout macros.h. The main problem lies with passing register names to the inline macros--the macro can't know which regsiters to add to the clobber list if it doesn't know which registers will be used as inputs and outputs. Per gcc docs, input and output registers can't appear in the clobber list. I gues it's time for a more clever way to produce gcc inlines (or just change the clobber list for all inline macros to "cc", "memory" unless a macro uses more than a jmp instruction). I guess I could start writing custom inlines as I need them. Eventually, I'll end up with a complete set of working inlines . . . but I don't think I want to write out inlines for every public API. Is fd2pragma more intelligent when it comes to producing inlines? Or does it use generic macros as well?

EDIT3: And it just occurred to me that gcc was optimizing away the functions when they weren't being referenced by the globals, which is why I wasn't getting the errors before (any why I shouldn't have optimizations turned on during development).

Trev
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Lots of responding to my own message. :-) As an example, here's a GCC 3.x friendly macro for ObtainSemaphore:

Code: [Select]

    (
        {
            struct SignalSemaphore * _ObtainSemaphore_v1 = (&mb->mb_Semaphore); {
                register struct Library *const _ObtainSemaphore_bn __asm(&quot;a6&quot;) = (struct Library*)(SysBase);
                register struct SignalSemaphore * _n1 __asm(&quot;a0&quot;) = _ObtainSemaphore_v1;
                __asm volatile (&quot;jsr a6@(-&quot;&quot;0x234&quot;&quot;:W)&quot; : : &quot;r&quot; (_ObtainSemaphore_bn), &quot;rf&quot;(_n1) : &quot;cc&quot;, &quot;memory&quot;);
            }
        }
    );


jsr doesn't modify CCR or memory, but I'm not sure if the clobber list applies to just the inline assembler block itself or any code that might be called while inside the block.

Trev
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
It looks like GCC 3.4.0 has problems with the macros that return values as well. There's a set of braces around the return value declaration. Here's LP1 as an example:

Code: [Select]

#define LP1(offs, rt, name, t1, v1, r1, bt, bn) \
({ \
   t1 _##name##_v1 = (v1); \
   { \
      register rt _##name##_re __asm(&quot;d0&quot;); \
      register struct Library *const _##name##_bn __asm(&quot;a6&quot;) = (struct Library*)(bn); \
      register t1 _n1 __asm(#r1) = _##name##_v1; \
      __asm volatile (&quot;jsr a6@(-&quot;#offs&quot;:W)&quot; \
      : &quot;=r&quot; (_##name##_re) \
      : &quot;r&quot; (_##name##_bn), &quot;rf&quot;(_n1) \
      : &quot;d0&quot;, &quot;d1&quot;, &quot;a0&quot;, &quot;a1&quot;, &quot;fp0&quot;, &quot;fp1&quot;, &quot;cc&quot;, &quot;memory&quot;); \
      _##name##_re; \
   } \
})


Since the return value is braced, it falls out of scope before it can be assigned to an lvalue. Anyhow, quick fix:

Code: [Select]

#define LP1(offs, rt, name, t1, v1, r1, bt, bn) \
({ \
   t1 _##name##_v1 = (v1); \
      register rt _##name##_re __asm("d0"); \
      register struct Library *const _##name##_bn __asm("a6") = (struct Library*)(bn); \
      register t1 _n1 __asm(#r1) = _##name##_v1; \
      __asm volatile ("jsr a6@(-"#offs":W)" \
      : "=r" (_##name##_re) \
      : "r" (_##name##_bn), "rf"(_n1) \
      : "cc", "memory"); \
      _##name##_re; \
})


I can't be the only running into these problems. . . . :-/

Trev
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
OK. Looks like the latest fd2pragma package has already fixed this stuff. Time to rebuild those inlines. . . .
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Uhhuh, yeah the idea was to #define SysBase ..., not ExecBase. Anyway, you found the real problem already.
 

Offline TrevTopic starter

  • Hero Member
  • *****
  • Join Date: May 2003
  • Posts: 1550
  • Country: 00
    • Show only replies by Trev
Now, if I could just get my library to load via OpenLibrary(), I'd be set. :-P The version command works, so it's finding the romtag structure. [looking] I was referencing my LibInit function instead of my init table in the romtag. Fixed now, but still can't load library. :-(