Bug 11807 - GCC should error out when clobbering the stack pointer and frame pointer
Summary: GCC should error out when clobbering the stack pointer and frame pointer
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: inline-asm (show other bugs)
Version: 3.3
: P2 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid
: 13079 23313 30579 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-08-05 12:45 UTC by Alex Warg
Modified: 2018-12-20 15:09 UTC (History)
8 users (show)

See Also:
Host: i686-pc-linux
Target:
Build: i686-pc-linux
Known to work:
Known to fail:
Last reconfirmed: 2005-12-15 04:58:48


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Warg 2003-08-05 12:45:28 UTC
The compiler seems to use not or wrong initialized registers for memory references.

1. # arm-linux-g++ -v
Reading specs from /usr/local/lib/gcc-lib/arm-linux/3.3/specs
Configured with: ./configure --prefix=/usr/local --target=arm-linux
--with-newlib --enable-languages=c,c++ --disable-libgcj --program-suffix=-3.3 -v
: (reconfigured) ./configure --prefix=/usr/local --target=arm-linux
--exec-prefix=/usr/local/arm-linux --with-newlib --enable-languages=c,c++
--disable-libgcj --program-suffix=-3.3 -v : (reconfigured) ./configure
--prefix=/usr/local --target=arm-linux --exec-prefix=/usr/local --with-newlib
--enable-languages=c,c++ --disable-libgcj -v : (reconfigured) ./configure
--prefix=/usr/local --target=arm-linux --exec-prefix=/usr/local --with-newlib
--enable-languages=c,c++ --disable-libgcj -v : (reconfigured) ./configure
--prefix=/usr/local --target=arm-linux --exec-prefix=/usr/local --with-newlib
--enable-languages=c,c++ --disable-libgcj -v : (reconfigured) ./configure
--prefix=/usr/local --target=arm-linux --exec-prefix=/usr/local --with-newlib
--enable-languages=c,c++ --disable-libgcj --disable-threads -v
Thread model: single
gcc version 3.3

Command line:
arm-linux-g++ -c -MD -nostdinc -I../src/types/arm -I../src/types      \
-I../src/drivers/arm -I../src/drivers                                 \
-I../src/lib/minilibc/arm/include -I../src/lib/minilibc/include       \
-I../src/lib/lmm -I../src/lib/amm -I../src/boot                       \
-I../src/kern/arm -I../src/kern -I../src/lib/libk/arm                 \
-I../src/lib/libk -I. -Iauto                                          \
-I/usr/local/lib/gcc-lib/arm-linux/3.3//include -W -Wall -fno-rtti    \
-fno-exceptions   -fno-defer-pop -freg-struct-return -g -Wall -W      \
-frename-registers -finline-limit=10000 -O1 ../src/sigma0-arm/test.cc \
-o test.o

Compiler output:
../src/sigma0-arm/test.cc: In function `int main()':
../src/sigma0-arm/test.cc:21: warning: unused variable `l4_threadid_t my_pager'
../src/sigma0-arm/test.cc:21: warning: unused variable `l4_threadid_t 
   my_preempter'
../src/sigma0-arm/test.cc: In function `void thread_action(unsigned int, 
   unsigned int, unsigned int)':
../src/sigma0-arm/test.cc:85: warning: unused parameter `unsigned int b'
../src/sigma0-arm/test.cc:85: warning: unused parameter `unsigned int c'

Preprocessed file: (test.ii)
# 1 "../src/sigma0-arm/test.cc"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "../src/sigma0-arm/test.cc"
# 1 "../src/lib/minilibc/include/cstdio" 1
# 1 "../src/lib/minilibc/include/stdio.h" 1
# 1 "../src/lib/minilibc/include/cdefs.h" 1
# 5 "../src/lib/minilibc/include/stdio.h" 2
# 1 "/usr/local/lib/gcc-lib/arm-linux/3.3/include/stddef.h" 1
# 151 "/usr/local/lib/gcc-lib/arm-linux/3.3/include/stddef.h"
typedef int ptrdiff_t;
# 213 "/usr/local/lib/gcc-lib/arm-linux/3.3/include/stddef.h"
typedef unsigned int size_t;
# 6 "../src/lib/minilibc/include/stdio.h" 2
# 1 "../src/lib/minilibc/include/mini_defs.h" 1
# 7 "../src/lib/minilibc/include/stdio.h" 2
extern "C" {
int putchar(int c);
int puts(const char *s);
int putstr(const char *const s);
int putnstr( const char *const c, int len );
int printf(const char *format, ...) __attribute__((format(printf,1,2)));
int sprintf(char *str, const char *format, ...) __attribute__((format(printf,2,3)));
int snprintf(char *str, size_t size, const char *format, ...)
__attribute__((format(printf,3,4)));
int asprintf(char **ptr, const char* format, ...)
__attribute__((format(printf,2,3)));

# 1 "../src/lib/minilibc/include/stdarg.h" 1
# 9 "../src/lib/minilibc/include/stdarg.h"
pedef __builtin_va_list va_list;
# 25 "../src/lib/minilibc/include/stdio.h" 2

int vprintf(const char *format, va_list ap) __attribute__((format(printf,1,0)));
int vsprintf(char *str, const char *format, va_list ap)
__attribute__((format(printf,2,0)));
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
__attribute__((format(printf,3,0)));

typedef int FILE;

int getchar(void);
char *gets(char *s) __attribute__((deprecated));
char *fgets(char *s, int size, FILE *stream);

int vscanf(const char *format, va_list ap) __attribute__((format(scanf,1,0)));
int vsscanf(const char *str, const char *format, va_list ap)
__attribute__((format(scanf,2,0)));

int sscanf(const char *str, const char *format, ...);

}
# 7 "../src/lib/minilibc/include/cstdio" 2

namespace std {
  using ::putchar;
  using ::puts;
  using ::putstr;
  using ::putnstr;
  using ::printf;
  using ::sprintf;
  using ::snprintf;
  using ::asprintf;
  using ::sscanf;

  using ::vprintf;
  using ::vsprintf;
  using ::vsnprintf;
  using ::getchar;
  using ::gets;
  using ::fgets;
  using ::vscanf;
  using ::vsscanf;

};
# 2 "../src/sigma0-arm/test.cc" 2
# 1 "../src/types/types.h" 1
# 11 "../src/types/types.h"
# 1 "/usr/local/lib/gcc-lib/arm-linux/3.3/include/stddef.h" 1
# 12 "../src/types/types.h" 2
# 1 "../src/types/arm/types-arch.h" 1
# 15 "../src/types/arm/types-arch.h"
typedef unsigned char Unsigned8;
typedef signed char Signed8;
typedef unsigned short Unsigned16;
typedef signed short Signed16;
typedef unsigned int Unsigned32;
typedef signed int Signed32;
typedef unsigned long long int Unsigned64;
typedef signed long long int Signed64;
typedef Signed32 Smword;
typedef Unsigned32 Mword;
typedef Unsigned32 Address;
typedef Unsigned64 Cpu_time;
# 13 "../src/types/types.h" 2
template< typename a, typename b > inline
a nonull_static_cast( b p )
{
  int d = reinterpret_cast<int>(static_cast<a>(reinterpret_cast<b>(10))) - 10;
  return reinterpret_cast<a>( reinterpret_cast<Mword>(p) + d );
}
typedef struct { Unsigned32 low, high; } l4_low_high_t;
typedef struct { Address low, high; } l4_addr_range_t;
typedef Smword ssize_t;
# 3 "../src/sigma0-arm/test.cc" 2
# 1 "../src/sigma0-arm/syscalls.h" 1
# 33 "../src/sigma0-arm/syscalls.h"
extern "C" {
# 44 "../src/sigma0-arm/syscalls.h"
typedef Unsigned64 cpu_time_t;
typedef struct {
    unsigned prio:8;
    unsigned small:8;
    unsigned zero:4;
    unsigned time_exp:4;
    unsigned time_man:8;
} l4_sched_param_struct_t;
typedef union {
    Mword sched_param;
    l4_sched_param_struct_t sp;
} l4_sched_param_t;
typedef struct {
    unsigned grant:1;
    unsigned write:1;
    unsigned size:6;
    unsigned zero:4;
    unsigned page:20;
} l4_fpage_struct_t;
typedef union {
    Mword raw;
    l4_fpage_struct_t fp;
} l4_fpage_t;
typedef struct {
    Mword snd_size;
    Mword snd_str;
    Mword rcv_size;
    Mword rcv_str;
} l4_strdope_t;
typedef union {
    struct {
        unsigned version : 10;
        unsigned thread : 6;
        unsigned task : 8;
        unsigned chief : 8;
    } id;
    Mword raw;
} l4_threadid_t;
typedef struct {
  unsigned rcv_exp:4;
  unsigned snd_exp:4;
  unsigned rcv_pfault:4;
  unsigned snd_pfault:4;
  unsigned snd_man:8;
  unsigned rcv_man:8;
} l4_timeout_struct_t;
typedef union {
  Mword raw;
  l4_timeout_struct_t timeout;
} l4_timeout_t;
# 121 "../src/sigma0-arm/syscalls.h"
typedef union
{
    struct {
        Mword msg_deceited :1;
        Mword fpage_received :1;
        Mword msg_redirected :1;
        Mword src_inside :1;
        Mword error_code :4;
        Mword strings :5;
        Mword dwords :19;
    } md;
    Mword raw;
} l4_msgdope_t;
# 173 "../src/sigma0-arm/syscalls.h"
extern __inline__ l4_threadid_t l4_myself (void);
extern __inline__ int l4_nchief (l4_threadid_t destination,
                                 l4_threadid_t *next_chief);
extern __inline__ void l4_fpage_unmap (l4_fpage_t fpage,
                                       Mword mask);
extern __inline__ l4_fpage_t l4_fpage (Mword address,
                                       Mword size,
                                       Mword write,
                                       Mword grant);
extern __inline__ void l4_thread_switch (l4_threadid_t destintaion);
extern __inline__ void l4_yield (void);
extern __inline__ void l4_thread_ex_regs (l4_threadid_t destination,
                                          Mword ip,
                                          Mword sp,
                                          l4_threadid_t *preempter,
                                          l4_threadid_t *pager,
                                          Mword *old_ip,
                                          Mword *old_sp,
                                          Mword *old_cpsr);

extern __inline__ void l4_task_new (l4_threadid_t dest,
                                    Mword mcp,
                                    Mword usp,
                                    Mword uip,
                                    l4_threadid_t pager);

extern __inline__ cpu_time_t l4_thread_schedule(l4_threadid_t dest,
                                                l4_sched_param_t param,
                                                l4_threadid_t *ext_preempter,
                                                l4_threadid_t *partner,
                                                l4_sched_param_t *old_param);
# 253 "../src/sigma0-arm/syscalls.h"
extern __inline__ void outstring(const char* x)
{
    __asm__ __volatile__ (
        "	mov	r0, %1		\n"
        "	mov	lr, pc		\n"
        "	mov	pc, %0		\n"
        "	cmp	lr, #2		\n"
        :
        : "i" ((-0x00000020-8)), "r"(x)
        : "r0", "lr");
}

extern __inline__ void outnstring(const char* x, unsigned len)
{
    __asm__ __volatile__ (
        "	mov	r0, %1		\n"
        "       mov     r1, %2          \n"
        "	mov	lr, pc		\n"
        "	mov	pc, %0		\n"
        "	cmp	lr, #3		\n"
        :
        : "i" ((-0x00000020-8)), "r"(x), "r"(len)
        : "r0", "r1", "lr");
}


extern __inline__ void outdec(const Mword x )
{
  (void)x;
}

extern __inline__ void kd_display(const char* x)
{
  (void)x;
}

extern __inline__ char kd_inchar()
{
    char c;
    __asm__ __volatile__ (
        "	mov	lr, pc		\n"
        "	mov	pc, %1		\n"
        "	cmp	lr, #13		\n"
        "	mov	%0, r0		\n"
        : "=r" (c)
        : "i" ((-0x00000020-8))
        : "r0", "lr");
    return c;
}
# 310 "../src/sigma0-arm/syscalls.h"
extern __inline__ l4_threadid_t l4_myself(void)
{
    l4_threadid_t id;

    asm volatile
      (
             " stmdb sp!, {fp} \n"
       "	mov	r0, %2					\n"
       "	mov	lr, pc					\n"
       "	mov	pc, %1					\n"
       "	mov	%0, r1					\n"
             " ldmia sp!, {fp} \n"
       :"=r" (id)
       :"i" ((-0x00000008-8)),
       "i" (((l4_threadid_t) { raw : 0 }).raw)
       :"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
       "r10", "r11", "r12", "r14", "memory");

    return id;
}
extern __inline__ void l4_fpage_unmap(l4_fpage_t fpage, Mword mask)
{
    __asm__ __volatile__
      (
       " stmdb sp!, {fp} \n"
       "	mov	r0, %1		@ l4_fpage_unmap	\n"
       "	mov	r1, %2					\n"
       "	mov	pc, %0					\n"
       " ldmia sp!, {fp} \n"
       :
       :"i" ((-0x0000000C-8)),
       "ri" (fpage.raw),
       "ri" (mask)
       :"r0", "r1", "r4", "r5", "r6", "r7", "r8", "r9",
       "r10", "r11", "r12", "r14", "memory");
}
extern __inline__ l4_fpage_t l4_fpage(Mword address,
                                      Mword size,
                                      Mword write,
                                      Mword grant)
{
    return ((l4_fpage_t){fp:{grant, write, size, 0,
                                 (address & 0xfffff000U) >> 12 }});
}

extern __inline__ void l4_thread_switch(l4_threadid_t dest)
{
    __asm__ __volatile__
      (
       " stmdb sp!, {fp} \n"
       "	mov	r0, %1		@ l4_thread_switch	\n"
       "	mov	lr, pc					\n"
       "	mov	pc, %0					\n"
       " ldmia sp!, {fp} \n"
        :
        :"i" ((-0x00000010-8)),
         "r" (dest)
        :"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
         "r10", "r11", "r12", "r14", "memory");
}
extern __inline__ void l4_yield(void)
{
    l4_thread_switch(((l4_threadid_t) { raw : 0 }));
}
extern __inline__ void l4_thread_ex_regs(l4_threadid_t destination,            
                                                                               
                                        
  Mword ip, Mword sp,                                                          
                                                                     
l4_threadid_t *preempter,                                                      
                                                                         
l4_threadid_t *pager,
                                                                               
                                                 Mword *old_ip,
                                                                               
                                                 Mword *old_sp,
                                                                               
                                                 Mword *old_cpsr){

        register Mword _dst asm("r0") = destination.id.thread;
        register Mword _ip asm("r1") = ip;
        register Mword _sp asm("r2") = sp;
        register Mword _pager asm("r3") = pager->raw;
        register Mword _flags asm("r4");

        (void)preempter;

        __asm__ __volatile__
                (



                 " ldr r10, [sp,#24] \n"
                 " stmdb sp!, {fp} \n"
                 "	mov	lr, pc					\n"
                 "	mov	pc, %5					\n"
                 " ldmia sp!, {fp} \n"






                 :
                 "=r" (_dst),
                 "=r" (_ip),
                 "=r" (_sp),
                 "=r" (_pager),
                 "=r" (_flags)
                 :
                 "i" ((-0x00000018-8)),
                 "0" (_dst),
                 "1" (_ip),
                 "2" (_sp),
                 "3" (_pager)
                 :
                 "r5", "r6", "r7", "r8", "r9",
                 "r10", "r11", "r12", "r14", "memory");

        if(pager) pager->raw = _pager;
        if(old_ip) *old_ip = _ip;
        if(old_sp) *old_sp = _sp;
        if(old_cpsr) *old_cpsr = _flags;
}


extern __inline__ void l4_task_new(l4_threadid_t dest,
                                                                               
                         Mword mcp,
                                                                               
                         Mword usp,
                                                                               
                         Mword uip,
                                                                               
                         l4_threadid_t pager)
{
        Mword x[] = {dest.raw, mcp, pager.raw, uip, usp};

        __asm__ __volatile__
                (
                 "	/* l4_task_new() */		\n"
                 "	ldr	r0, %1			\n"
                 "	ldr	r1, %2			\n"
                 "	ldr	r2, %3			\n"
                 "	ldr	r3, %4			\n"
                 "	ldr	r4, %5			\n"
                 " stmdb sp!, {fp} \n"
                 "	mov	lr, pc			\n"
                 "	mov	pc, %0			\n"
                 " ldmia sp!, {fp} \n"
                 :
                 :"i" ((-0x0000001C-8)),
                 "m" (x[0]), "m" (x[1]), "m" (x[2]), "m" (x[3]), "m" (x[4])
                 :"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
                 "r10", "r11", "r12", "r14", "memory");

}


extern __inline__ cpu_time_t l4_thread_schedule(l4_threadid_t dest,
                                        l4_sched_param_t param,
                                        l4_threadid_t *ext_preempter,
                                        l4_threadid_t *partner,
                                        l4_sched_param_t *old_param)
{

  (void)ext_preempter;
    __asm__ __volatile__ (
        "/* l4_thread_schedule */				\n"
       " stmdb sp!, {fp} \n"
        "	mov	r0, %4					\n"
        "	mov	r1, %3					\n"

        "	mov	lr, pc					\n"
        "	mov	pc, %2					\n"

        "	mov	r0, %1					\n"
        " ldmia sp!, {fp} \n"


        :"=r" (partner),
         "=r" (*old_param)
        :"i" ((-0x00000014-8)),
         "r" (dest),
         "r" (param)
        :"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
        "r10", "r11", "r12", "r14");

    return 0;
}



extern __inline__ int l4_ipc_wait(l4_threadid_t *src,
                          void *rcv_msg,
                          Mword *rcv_dword0,
                          Mword *rcv_dword1,
                          Mword *rcv_dword2,
                          l4_timeout_t timeout,
                          l4_msgdope_t *result)
{
    union {
        struct {
            Mword rcv;
            l4_timeout_t timeout;
        } in;
        struct {
            Mword dw0;
            Mword dw1;
            Mword dw2;
            l4_threadid_t src;
            l4_msgdope_t result;
        } out;
    } x = { in: {((Mword) rcv_msg | 1), timeout}};


    asm volatile(

        "/* l4_ipc_wait(start) */	\n"
        "	ldr	r2, %1		\n"
        "	ldr	r3, %7		\n"
        "	mov	r1, #0xFFFFFFFF	\n"
        " stmdb sp!, {fp} \n"
        "	mov	lr, pc		\n"
        "	mov	pc, %0		\n"
        " ldmia sp!, {fp} \n"
        "	str	r0, %6		\n"
        "	str	r1, %2		\n"
        "	str	r4, %3		\n"
        "	str	r5, %4		\n"
        "	str	r6, %5		\n"
        "\t/* l4_ipc_wait(end) */	\n"
        :
        : "i" ((-0x00000004-8)),
        "m" (x.in.rcv),
        "m" (x.out.src),
        "m" (x.out.dw0),
        "m" (x.out.dw1),
        "m" (x.out.dw2),
        "m" (x.out.result),
        "m" (x.in.timeout)
        : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
         "r10", "r11", "r12", "r14", "memory");
    *rcv_dword0 = x.out.dw0;
    *rcv_dword1 = x.out.dw1;
    *rcv_dword2 = x.out.dw2;
    *result = x.out.result;
    *src = x.out.src;

    return result->md.error_code;
}



extern __inline__ int l4_ipc_receive(l4_threadid_t src,
                             void *rcv_msg,
                             Mword *rcv_dword0,
                             Mword *rcv_dword1,
                             Mword *rcv_dword2,
                             l4_timeout_t timeout,
                             l4_msgdope_t *result)
{
    union {
        struct {
            l4_threadid_t src;
            Mword rcv;
            l4_timeout_t timeout;
        } in;
        struct {
            Mword dw0;
            Mword dw1;
            Mword dw2;
            l4_msgdope_t result;
        } out;
  } x = { in: {src, (Mword) rcv_msg, timeout}};


    asm volatile(

        "/* l4_ipc_receive(start) */	\n"
        "	ldr	r1, %2		\n"
        "	ldr	r2, %1		\n"
        "	ldr	r3, %7		\n"
        "	mov	r1, #0xFFFFFFFF	\n"
        " stmdb sp!, {fp} \n"
        "	mov	lr, pc		\n"
        "	mov	pc, %0		\n"
        " ldmia sp!, {fp} \n"
        "	str	r0, %6		\n"
        "	str	r1, %2		\n"
        "	str	r4, %3		\n"
        "	str	r5, %4		\n"
        "	str	r6, %5		\n"
        "\t/* l4_ipc_receive(end) */	\n"
        :
        : "i" ((-0x00000004-8)),
        "m" (x.in.rcv),
        "m" (x.in.src),
        "m" (x.out.dw0),
        "m" (x.out.dw1),
        "m" (x.out.dw2),
        "m" (x.out.result),
        "m" (x.in.timeout)
        : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
         "r10", "r11", "r12", "r14", "memory"
        );
    *rcv_dword0 = x.out.dw0;
    *rcv_dword1 = x.out.dw1;
    *rcv_dword2 = x.out.dw2;
    *result = x.out.result;




    return result->md.error_code;
}



extern __inline__ int l4_ipc_send(l4_threadid_t dest,
                                                                               
                        const void *snd_msg,
                                                                               
                        Mword w0,
                                                                               
                        Mword w1,
                                                                               
                        Mword w2,
                                                                               
                        l4_timeout_t timeout,
                                                                               
                        l4_msgdope_t *result)
{

        register Mword _dest asm("r0") = dest.raw;
        register Mword _snd_msg asm("r1") = (Mword)snd_msg;
        register Mword _rcv_desc asm("r2") = ~0U;
        register Mword _timeout asm("r3") = timeout.raw;
        register Mword _w0 asm("r4") = w0;
        register Mword _w1 asm("r5") = w1;
        register Mword _w2 asm("r6") = w2;

        __asm__ __volatile__
                ("/* l4_ipc_send(start) */\n\t"
                 "   stmdb sp!, {fp}      \n\t"
                 "	 mov	lr, pc			 \n\t"
                 "	 mov	pc, %7			 \n\t"
                 "   ldmia sp!, {fp}      \n\t"
                 "	 str	r0, %8			 \n\t"
                 "/*l4_ipc_send(end) */   \n\t"
                 :
                 "=r" (_dest),
                 "=r" (_snd_msg),
                 "=r" (_rcv_desc),
                 "=r" (_timeout),
                 "=r" (_w0),
                 "=r" (_w1),
                 "=r" (_w2)
                 :
                 "i" ((-0x00000004-8)),
                 "m" (*result),
                 "0" (_dest),
                 "1" (_snd_msg),
                 "2" (_rcv_desc),
                 "3" (_timeout),

                 "4" (_w0),
                 "5" (_w1),
                 "6" (_w2)
                 :
                 "r7", "r8", "r9", "r10", "r11", "r12", "r14", "memory"
                 );

        return result->md.error_code;
}



extern __inline__ int l4_ipc_call(l4_threadid_t dest,
                          const void *snd_msg,
                          Mword snd_dword0,
                          Mword snd_dword1,
                          Mword snd_dword2,
                          void *rcv_msg,
                          Mword *rcv_dword0,
                          Mword *rcv_dword1,
                          Mword *rcv_dword2,
                          l4_timeout_t timeout,
                          l4_msgdope_t *result)
{
    struct
    {
        Mword tid;
        Mword snd_dsc;
        Mword rcv_dsc;
        Mword timeout;
        Mword dw0;
        Mword dw1;
        Mword dw2;
        l4_msgdope_t result;
    } x = {dest.raw, (Mword) snd_msg, (Mword) rcv_msg, timeout.raw,
           snd_dword0, snd_dword1, snd_dword2 , {raw: 0}};

    __asm__ __volatile__ (

        "/* l4_ipc_call(start) */		\n"
        "	ldr	r0, %1			\n"
        "	ldr	r1, %2			\n"
        "	ldr	r2, %3			\n"
        "	ldr	r3, %8			\n"
        "	ldr	r4, %4			\n"
        "	ldr	r5, %5			\n"
        "	ldr	r6, %6			\n"
        " stmdb sp!, {fp} \n"
        "	mov	lr, pc			\n"
        "	mov	pc, %0			\n"
        " ldmia sp!, {fp} \n"
        "	str	r0, %7			\n"
        "	str	r4, %4			\n"
        "	str	r5, %5			\n"
        "	str	r6, %6			\n"
        "\t/*l4_ipc_call(end) */		\n"
        :
        : "i" ((-0x00000004-8)),
        "m" (x.tid),
        "m" (x.snd_dsc),
        "m" (x.rcv_dsc),
        "m" (x.dw0),
        "m" (x.dw1),
        "m" (x.dw2),
        "m" (x.result),
        "m" (x.timeout)
        :"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
         "r10", "r11", "r12", "r14", "memory");
    *rcv_dword0 = x.dw0;
    *rcv_dword1 = x.dw1;
    *rcv_dword2 = x.dw2;
    *result = x.result;

    return result->md.error_code;
}



extern __inline__ int l4_ipc_reply_and_wait(l4_threadid_t dest,
                                    const void *snd_msg,
                                    Mword snd_dword0,
                                    Mword snd_dword1,
                                    Mword snd_dword2,
                                    l4_threadid_t *src,
                                    void *rcv_msg,
                                    Mword *rcv_dword0,
                                    Mword *rcv_dword1,
                                    Mword *rcv_dword2,
                                    l4_timeout_t timeout,
                                    l4_msgdope_t *result)
{
    struct
    {
        Mword tid;
        Mword snd_dsc;
        Mword rcv_dsc;
        l4_timeout_t timeout;
        Mword dw0;
        Mword dw1;
        Mword dw2;
        l4_msgdope_t result;
    } x = {dest.raw, (Mword) snd_msg, (Mword) rcv_msg | 1,
           timeout, snd_dword0, snd_dword1, snd_dword2, {raw: 0}};

    __asm__ __volatile__ (

        "/* l4_ipc_reply_and_wait(start) */	\n"
        "	ldr	r0, %1			\n"
        "	ldr	r1, %2			\n"
        "	ldr	r2, %3			\n"
        "	ldr	r3, %8			\n"
        "	ldr	r4, %4			\n"
        "	ldr	r5, %5			\n"
        "	ldr	r6, %6			\n"
       " stmdb sp!, {fp} \n"
        "	mov	lr, pc			\n"
        "	mov	pc, %0			\n"
        " ldmia sp!, {fp} \n"
        "	str	r0, %7			\n"
        "	str	r1, %1			\n"
        "	str	r4, %4			\n"
        "	str	r5, %5			\n"
        "	str	r6, %6			\n"
        "\t/*l4_ipc_reply_and_wait(end) */	\n"
        :
        : "i" ((-0x00000004-8)),
        "m" (x.tid),
        "m" (x.snd_dsc),
        "m" (x.rcv_dsc),
        "m" (x.dw0),
        "m" (x.dw1),
        "m" (x.dw2),
        "m" (x.result),
        "m" (x.timeout)
        :"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
         "r10", "r11", "r12", "r14", "memory");
    *rcv_dword0 = x.dw0;
    *rcv_dword1 = x.dw1;
    *rcv_dword2 = x.dw2;
    src->raw = x.tid;
    *result = x.result;

    return result->md.error_code;
    return 0;
}



}
# 4 "../src/sigma0-arm/test.cc" 2







Mword stack[1024];

extern "C" {
void thread_action(unsigned sta, unsigned, unsigned);
void thread_action_asm();
}

int main()
{

  l4_threadid_t my_pager, my_preempter, myself, dst;
  l4_threadid_t sigma0;
  sigma0.raw = 0;
  sigma0.id.task=2;
  dst.raw = 0;
  dst.id.task=4;
  dst.id.thread=1;

  myself = l4_myself();


  int x=0;
  Mword d1,d2,d3;
  l4_msgdope_t result;




  printf("TEST[""%d.%d""]: Start thread ""%d.%d"": sp= %p\n", (myself).id.task,
(myself).id.thread,(dst).id.task, (dst).id.thread,stack);
  printf("TEST: pager= %08x, ""%d.%d""\n",sigma0.raw,(sigma0).id.task,
(sigma0).id.thread);
  l4_thread_ex_regs(dst,(Mword)&thread_action_asm,(Mword)(stack+1020),
&((l4_threadid_t) { raw : ~0 }),&sigma0,
                    0,0,0 );

  printf("TEST[""%d.%d""]: Start should be up\n", (myself).id.task,
(myself).id.thread);




  if(l4_ipc_send(dst, 0, d1, d2, d3, ((l4_timeout_t) { raw: 0}), &result)==0) {
          puts("SUCCESS");
  } else {
          puts("ERROR");
  }

  __asm__ __volatile__ ( "	mov	lr, pc		\n" "	mov	pc, %0		\n" "	b	1f		\n" "
.ascii	\"" "\"	\n" "	.byte	0		\n" "	.align	2		\n" "1:				\n" : : "i"
((-0x00000020-8)) : "lr");

  for(x=0;x<10;x++)
    {
      printf("TEST[""%d.%d""]: Hello World!\n", (myself).id.task,
(myself).id.thread );
      l4_ipc_receive(((l4_threadid_t) { raw : 0 }), 0, &d1, &d2, &d3,
                     ( (l4_timeout_t) {timeout: { 9, 0, 0, 0, 0, 122 } } ),
&result);

    }




  thread_action(10,20,30);

  return 1;

}

asm
(".text                    \n"
 ".globl thread_action_asm \n"
 "thread_action_asm:       \n"
 "   mov r0, sp            \n"
 "   adr sp, 1f            \n"
 "   ldr sp, [sp]          \n"
 "   b thread_action       \n"
 "1: .word stack+4096      \n");

extern "C" __attribute__((noinline)) void thread_action(unsigned sta,unsigned b,
unsigned c)
{
  Mword d1,d2,d3;
  l4_msgdope_t result;
  l4_threadid_t myself, other;
  myself = l4_myself();
  other=myself;
  other.id.thread=0;
  printf("TEST[""%d.%d""]: thread_action (ostack=%08x)!!!\n", (myself).id.task,
(myself).id.thread,sta);
  printf("TEST[""%d.%d""]: waiting for ipc from ""%d.%d""\n", (myself).id.task,
(myself).id.thread,
                 (other).id.task, (other).id.thread);
  l4_ipc_receive(other,0,&d1,&d2,&d3, ((l4_timeout_t) { raw: 0}), &result);

  __asm__ __volatile__ ( "	mov	lr, pc		\n" "	mov	pc, %0		\n" "	b	1f		\n" "
.ascii	\"" "\"	\n" "	.byte	0		\n" "	.align	2		\n" "1:				\n" : : "i"
((-0x00000020-8)) : "lr");
  l4_ipc_receive(((l4_threadid_t) { raw : 0 }), 0, &d1, &d2, &d3,
                 ((l4_timeout_t) { raw: 0}), &result);
  return;
}
Comment 1 Andrew Pinski 2003-08-05 13:22:04 UTC
From <http://gcc.gnu.org/ml/gcc-bugs/2003-08/msg00669.html>:
fp (r11) is the Compiler's frame-pointer register.  You can't use it for 
your own purposes, the compiler cannot handle that.

So I am closing as invalid.
Comment 2 Alex Warg 2003-08-05 14:34:41 UTC
I'm not using fp explicitely in my code, as you can see in test.ii. I just
preserve it across system calls. The compiler uses fp to store non-pointer
values in fp and later uses it as pointer!

So it is seemingly a BUG.
Comment 3 Richard Earnshaw 2003-08-05 17:51:04 UTC
Subject: Re:  Wrong usage of registers on ARM 

> I'm not using fp explicitely in my code, as you can see in test.ii. I just
> preserve it across system calls. The compiler uses fp to store non-pointer
> values in fp and later uses it as pointer!
> 
> So it is seemingly a BUG.

No, this asm statement clobbers fp (or appears to):

extern __inline__ l4_threadid_t l4_myself(void)
{
    l4_threadid_t id;

    asm volatile
      (
             " stmdb sp!, {fp} \n"
       "	mov	r0, %2					\n"
       "	mov	lr, pc					\n"
       "	mov	pc, %1					\n"
       "	mov	%0, r1					\n"
             " ldmia sp!, {fp} \n"
       :"=r" (id)
       :"i" ((-0x00000008-8)),
       "i" (((l4_threadid_t) { raw : 0 }).raw)
       :"r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
       "r10", "r11", "r12", "r14", "memory");

    return id;
}

This *will* confuse the compiler.

R.

Comment 4 Falk Hueffner 2003-08-05 18:14:36 UTC
If gcc can't cope with the FP being clobbered, shouldn't it abort at compile
time rather than generating bogus code?
Comment 5 Andrew Pinski 2003-08-06 03:40:06 UTC
gcc does error when the PIC register is clobered so it should error out when the frame 
pointer or stack pointer is clobered.
An example for PPC:
int f()
{
  asm("addi r30, r30, 1":::"r30");
  asm("addi r1, r1, 1":::"r1");
}

I can confirm this on the mainline (20030805).
Comment 6 Dara Hazeghi 2003-08-23 00:00:55 UTC
Not a regression.
Comment 7 Andrew Pinski 2003-11-16 23:04:57 UTC
*** Bug 13079 has been marked as a duplicate of this bug. ***
Comment 8 Falk Hueffner 2003-11-17 11:49:07 UTC
Here's what I think:

1. No way we can support clobbering both SP and FP.
2. We could support clobbering the FP by pushing it onto the stack and restoring
   it. Doesn't seem worth the trouble, though, since people can do this
   themselves in the asm.
3. We could support clobbering the SP by introducing a FP and being very
   careful. I cannot see any useful application though, so it doesn't seem
   worth the trouble.

So I suggest a patch like this:

--- stmt.c~     2003-11-16 04:25:28.000000000 +0100
+++ stmt.c      2003-11-17 12:21:24.000000000 +0100
@@ -1524,13 +1524,17 @@
       /* Mark clobbered registers.  */
       if (i >= 0)
         {
-         /* Clobbering the PIC register is an error */
-         if (i == (int) PIC_OFFSET_TABLE_REGNUM)
-           {
-             error ("PIC register `%s' clobbered in `asm'", regname);
-             return;
-           }
-
+         switch (i) {
+         case PIC_OFFSET_TABLE_REGNUM:
+           error ("PIC register `%s' clobbered in `asm'", regname);
+           return;
+         case STACK_POINTER_REGNUM:
+           error ("Stack pointer register `%s' clobbered in `asm'", regname);
+           return;
+         case HARD_FRAME_POINTER_REGNUM:
+           error ("Frame pointer register `%s' clobbered in `asm'", regname);
+           return;
+         }
          SET_HARD_REG_BIT (clobbered_regs, i);
        }
     }

I have no time to test it currently, though.
Comment 9 Bryan Mills 2003-11-17 12:39:22 UTC
Presumably if the programmer is intentionally, explicitly clobbering the frame
pointer, the base pointer, or both using inline assembly, they are doing so
knowing full well what they are doing -- and are attempting to do something
unusual and specific with the stack.  We should certainly take this into
consideration when making decisions about what is the correct action for gcc to
take.

The assertion that there is no useful application for such clobbering is false,
as careful adjusting of the frame and base pointers in assembly interleaved with
struct/array accesses in C can produce fairly elegant context-switching code for
multiplexing between threads/processes.  Other applications may exist.

Given that this is the case, it seems that gcc should do one of the following to
provide "correct" behaviour:

1. (the obvious solution) Fail.  If this is the case it should be noted in the
inline assembly documentation that clobbering the frame or stack pointer will
result in a compile-time error.

2. (refinement of Falk's #2) Insert code to save the stack and/or frame pointers
in other registers before the clobber and restore them prior to usage (which
would entail some very sophisticated code and would probably frustrate
programmers who are intentionally abusing the stack discipline, but it would not
be unreasonable).  This doesn't seem like a viable solution, because it would
entail tracking changes through large sections of code and adding significant
amounts of extremely complex register copying, but would not add much in the way
of usefulness other than letting programmers use the stack and/or frame pointers
for arithmetic (not very useful at all).

3. (not considered in this thread so far, because it relies on the assumption
that the programmer knows they're munging the stack) Emit code for function
calls which takes the clobbering of the stack pointer into account when
generating function calls and returns -- don't over-write anything above the
stack pointer when making a function call, but allow arbitrary changes to the
frame pointer, being careful not to use it for any other arithmetic (setting the
frame pointer manually being tantamount to context-switching the execution of
the function).  This is arguably the most intuitive (and useful) behaviour (and
the one that has the most obvious application to context switching), although it
would also require quite a bit of fairly sophisticated code to track the changes
to the stack pointer enough to emit correct function calls.  This is possible to
implement, although it may be quite difficult given the GCC codebase.


I would suggest testing and implementing Falk's patch (solution #1) for now to
preserve correct compilation in the immediate future, with an eye toward
possibly implementing #3 at a later date.
Comment 10 Bryan Mills 2003-11-17 12:44:08 UTC
As a side note, someone should change the summary of this bug to reflect the
correct spelling of "clobbering", in case anyone (like me) searches for
"clobber" or "clobbering" when checking for previously reported bugs.  =P
Comment 11 Richard Henderson 2003-11-21 08:47:05 UTC
(In reply to comment #8)
> +         switch (i) {
> +         case PIC_OFFSET_TABLE_REGNUM:

Can't use a switch; PIC_OFFSET_TABLE_REGNUM is not constant.

> +         case HARD_FRAME_POINTER_REGNUM:
> +           error ("Frame pointer register `%s' clobbered in `asm'", regname);

This one's more interesting, since if CAN_DEBUG_WITHOUT_FP we often won't
need or use a frame pointer.  I think this error should be delayed until
reload has decided that a frame pointer is necessary.
Comment 12 Richard Henderson 2003-11-21 08:54:43 UTC
(In reply to comment #9)
> Presumably if the programmer is intentionally, explicitly clobbering
> the frame pointer, the base pointer, or both using inline assembly,
> they are doing so knowing full well what they are doing

I would say this is demonstrably false.  Indeed, I would say exactly
the opposite.  If they knew what they were doing, they would realize
that clobbering the frame pointer will throw the compiler into a 
tizzy and WILL NEVER WORK.

The nature of GCC's inline assembly is unfortunate.  It's extremely
powerful, but it exposes so much of compiler internals that you have
to know how the compiler works so as to avoid invalid corner cases.

> The assertion that there is no useful application for such clobbering
> is false, as careful adjusting of the frame and base pointers in
> assembly interleaved with struct/array accesses in C can produce ...

... a mess.  Use out-of-line assembly if you're going to be playing
with such stack frame fundamentals.
Comment 13 Bryan Mills 2003-11-21 09:55:58 UTC
(In reply to comment #12)
> > Presumably if the programmer is intentionally, explicitly clobbering
> > the frame pointer, the base pointer, or both using inline assembly,
> > they are doing so knowing full well what they are doing
>.... 
> If they knew what they were doing, they would realize
> that clobbering the frame pointer will throw the compiler into a 
> tizzy and WILL NEVER WORK.

Just because you know not to trust the compiler, that doesn't mean that trusting
the compiler to generate correct code is unreasonable.  There are two
assumptions that a programmer could make regarding the compiler: that the
compiler writer knows how their code works and has it behave in reasonable ways;
or that the compiler writer has forgotton or ignored some cases, which are
broken.  If the latter is the better assumption, no one should ever compile code
with GCC because they *may* be using broken features -- there's no way to
reliably tell which ones are and which ones aren't.  This is clearly not an
assumption that you want users to be making if you want your compiler to be
taken seriously.

Anything that can be fed successfully to the compiler should produce correct
output; it should never be possible to "throw the compiler into a tizzy",
because the compiler should have some well-defined behaviour for every allowable
piece of code that it processes.  It *does* have control over every line of code
it generates.

Your point here (and one that seems to be repeated far too often) seems to be
that no one should use a language in a subtle, unusual way -- which has clearly
not been the case, and probably never will be.  Programmers will always push the
system as far as it can go, and the system should (and historically has, for the
most part) be able to handle it.

In a compiler with a robust register allocator, it *is* possible for the
compiler to deal with these very sorts of edge cases in a well-defined and
intuitive manner, and whether they "work" in the sense that the programmer
intended or not, they should at the bare minimum "work" in the sense that they
do something anticipatable and rational (see comment #9 for suggestions of what
that well-defined, rational behaviour could be).  Some possibilities for dealing
with the frame pointer include saving before the clobber and restoring after,
and using a safer (and probably slower) stack discipline in the presence of
volatile stack frames.

If the code "WILL NEVER WORK" in the compiler, that's because the compiler
contains errors -- and errors should be corrected, not avoided.

> The nature of GCC's inline assembly is unfortunate.  It's extremely
> powerful, but it exposes so much of compiler internals that you have
> to know how the compiler works so as to avoid invalid corner cases.

Saying "it's ok for the compiler to generate invalid code because it's a corner
case" is equivalent to saying "Apache may immediately crash upon receiving a
malformed HTTP request" or "bash can accept strings into a buffer without
performing any buffer length checks", which are clearly false -- corner cases,
which have been thoroughly considered and handled in a robust manner (or at
least that's what we expect).  When it comes to programming, corner cases are a
fact of life -- and they have to be dealt with responsibly rather than swept
under the rug.  It is the compiler-writer's duty to resolve corner cases in the
compiler, not the programmer's -- they have their own set to worry about.

> > The assertion that there is no useful application for such clobbering
> > is false, as careful adjusting of the frame and base pointers in
> > assembly interleaved with struct/array accesses in C can produce ...
> 
> ... a mess.  Use out-of-line assembly if you're going to be playing
> with such stack frame fundamentals.

Once again, if the language accepted by the compiler contains unusual
constructs, they *must* be compiled correctly or else the compiler is *broken*.
 I have successfully written a context switch even in the presence of the
current stack frame bugs -- by doing so in a function with no local variables. 
If I were to re-write the code in pure assembly, I would either have to
completely commit myself to a particular, unrefinable data structure for storing
process information, or check all of my assembly offsets every time I made a
change.  If I didn't want to use the features of GCC to my advantage, I would
have written it in assembly to begin with -- but higher-level languages are much
more elegant, especially when large, complex data structures are concerned.
Comment 14 Falk Hueffner 2003-11-22 17:55:01 UTC
(In reply to comment #11)
> > +         case HARD_FRAME_POINTER_REGNUM:
> > +           error ("Frame pointer register `%s' clobbered in `asm'", regname);
> 
> This one's more interesting, since if CAN_DEBUG_WITHOUT_FP we often won't
> need or use a frame pointer.  I think this error should be delayed until
> reload has decided that a frame pointer is necessary.

Maybe. It's currently broken even for frameless, though, at least on
Alpha:

int f(int x) { asm ("nop" : : : "$15");  return x; }
        mov     a0,v0
        nop
        ret

even though $15/fp/s6 is a callee-saved register in frameless
functions.

Comment 15 Andrew Pinski 2003-12-06 20:09:12 UTC
The Frame pointer part is fixed by:
	* basic-block.h (PROP_ASM_SCAN): Define.
	* final.c (regs_asm_clobbered): New array.
	* regs.h (regs_asm_clobbered): Declare.
	* flow.c (life_analysis): Init it.
	(mark_set_regs): Set PROP_ASM_SCAN for asms.
	(mark_set_1): Set regs_asm_clobbered.
	* global.c (global_alloc): Don't set eliminable_regset when
	regs_asm_clobbered.

Comment 16 Andrew Pinski 2005-08-10 10:46:12 UTC
Frame pointer is still not fixed at -O0.
Comment 17 Andrew Pinski 2005-08-10 10:47:40 UTC
*** Bug 23313 has been marked as a duplicate of this bug. ***
Comment 18 Giovanni Bajo 2005-08-10 11:25:37 UTC
Small testcase from PR 23313, showing ICE on invalid:

-----------------------------------------
int main(){
    int i;

    asm (
        "xorl %%ebp, %%ebp\n\t"
        "movl %0, %%ebp\n\t"
        :: "m" (i)
        : "%ebp"
    );
    return 0;
}
-----------------------------------------

This makes this PR a bug, not simply an enhancement.
Comment 19 Andrew Pinski 2005-08-10 11:28:54 UTC
(In reply to comment #18)
> Small testcase from PR 23313, showing ICE on invalid:
the code does not ICE but creates "wrong code" at runtime.
Comment 20 Nigel Cunningham 2005-08-23 11:31:00 UTC
gcc shouldn't always error out in this situation. For suspend to disk, we
clobber all registers when restoring the original cpu context after copying back
the original kernel context. We could lie to gcc and say we don't clobber the
register, but I'd prefer to be honest :>

Nigel
Comment 21 Andrew Pinski 2005-08-23 11:34:48 UTC
(In reply to comment #20)
> gcc shouldn't always error out in this situation. For suspend to disk, we
> clobber all registers when restoring the original cpu context after copying back
> the original kernel context. We could lie to gcc and say we don't clobber the
> register, but I'd prefer to be honest :>

You know you can use a function to do that and a .s file for that right?  You don't need to use an inline-
asm, right?
Comment 22 ncunningham@cyclades.com 2005-08-23 11:41:26 UTC
Subject: Re:  GCC should error out when clobbering
	the stack pointer and frame pointer

The function needs to be inlined - the return value especially is
pivotal in the transition from the booted kernel context to the
suspended one. That said, I'm no x86 assembly guru, so there might be a
way around it.

Regards,

Nigel

On Tue, 2005-08-23 at 21:34, pinskia at gcc dot gnu dot org wrote:
> ------- Additional Comments From pinskia at gcc dot gnu dot org  2005-08-23 11:34 -------
> (In reply to comment #20)
> > gcc shouldn't always error out in this situation. For suspend to disk, we
> > clobber all registers when restoring the original cpu context after copying back
> > the original kernel context. We could lie to gcc and say we don't clobber the
> > register, but I'd prefer to be honest :>
> 
> You know you can use a function to do that and a .s file for that right?  You don't need to use an inline-
> asm, right?
Comment 23 Alex Warg 2005-08-26 09:13:49 UTC
GCC must error out when clobbering the frame pointer register because it is
likely to generate faulty code when the frame pointer is clobbered. You have to
save and restore the frame pointer on your own with (x86 push ebp; pop ebp). The
you need not to clobber it.

The only exception could possibly be the compiler option -fno-frame-pointer.
However at the moment GCC for arm generates faulty code even with this option,
if the frame pointer is clobbered.
Comment 24 Albert Cahalan 2006-04-21 02:11:16 UTC
PIC register: while the user could save and restore this, the whole point of this fancy assembly notation is so that gcc can do nice scheduling and register allocation. The save and restore should thus be done by gcc. Perhaps the PIC register won't soon be needed, so gcc could use it for something else until it gets reloaded with the normal content. At the very least, gcc could pick a good location for the save/restore operations.

Frame pointer register: this is the same as the PIC register. It's good to schedule the save/restore nicely.

Stack pointer register: this one is special. For app code, signals may arrive. For kernel code, interrupts might be delivered without a stack change. Not supporting a clobbered stack pointer is definitely tolerable. Ideally this case could be handled (making the code non-reentrant), but the resulting mess is probably of very limited use. I could imagine abusing push/pop to iterate over arrays, but that's insane.
Comment 25 Martin von Gagern 2006-08-10 21:48:32 UTC
(In reply to comment #8)
> 1. No way we can support clobbering both SP and FP.

You could in theory by storing one of them to some fixed memory location. But here things get really ugly, so this is more of a philosophical answer.

> 2. We could support clobbering the FP by pushing it onto the stack and
>    restoring it. Doesn't seem worth the trouble, though, since people can
>    do this themselves in the asm.

Not necessarily. For x86 with -fomit-frame-pointer, local variables are usually adressed relative to SP. If you push FP onto the stack, you modify SP, and operands are prehaps no longer accessible. If gcc would store FP on the stack, it could take the offset into account and make things work.

By the way, the same is imo true for the x86 PIC register ebx, which I would like to see clobberable and stored by gcc as well. Saving and restoring ebx in asm can be a real pain for the above reason. It would be great if the compiler additionaly would ensure that no other operand is an address relative to ebx.

> 3. We could support clobbering the SP by introducing a FP and being very
>    careful. I cannot see any useful application though, so it doesn't seem
>    worth the trouble.

One useful application would be in the sense of "no clobber register may overlap with any of the other operands". You could place the SP on the clobber list to indicate that you are going to modify it, and gcc could then try to avoid emitting SP-relative operands, e.g. by making them FP-relative or shouting if this is not possible.

You might even think of this in the sense of "a clobbered register may contain any data at the end of the asm". That would be asm code that uses the stack, but  does not clean up afterwards. You could in many cases restore the SP as a fixed offset from the FP, to allow such asm code.

BTW: The test case I just wrote for bug 28686 exhibits this problem here as well, along with two other issues.
Comment 26 Andrew Pinski 2007-01-25 01:02:08 UTC
*** Bug 30579 has been marked as a duplicate of this bug. ***
Comment 27 David Mendenhall 2007-01-30 18:20:33 UTC
Bug 30579 was marked as a duplicate of this bug. If I compile the test case from that bug with -fomit-frame-pointer, gcc still generates invalid code. (We don't use frame pointers in our system at all). Is this already known? It seems like gcc should support clobbering of fp if you've disabled frame pointers.