Factor Language Blog

gcc is open sores software

Friday, August 17, 2007

In Factor 0.90, I added a new function to vm/os-linux.c which returns the path of the current executable. However it seems that neither gcc 4.0.3 nor gcc 4.2.1 can compile this file on x86. I get an error like the following:

vm/os-linux.c: In function 'vm_executable_path_and':
vm/os-linux.c:20: error: unable to find a register to spill in class 'DIREG'
vm/os-linux.c:20: error: this is the insn:
(insn:HI 16 83 17 2 (parallel [
            (set (reg:SI 2 cx [66])
                (unspec:SI [
                        (mem:BLK (reg/v/f:SI 63 [ suffix ]) [0 A8])
                        (reg:QI 0 ax [70])
                        (const_int 1 [0x1])
                        (reg:SI 2 cx [69])
                    ] 20))
            (use (reg:SI 19 dirflag))
            (clobber (reg/f:SI 68 [ suffix ]))
            (clobber (reg:CC 17 flags))
        ]) 530 {*strlenqi_1} (insn_list:REG_DEP_TRUE 6 (insn_list:REG_DEP_TRUE 12 (insn_list:REG_DEP_TRUE 14 (insn_list:REG_DEP_TRUE 15 (nil)))))
    (expr_list:REG_DEAD (reg:SI 19 dirflag)
        (expr_list:REG_DEAD (reg:SI 2 cx [69])
            (expr_list:REG_DEAD (reg:QI 0 ax [70])
                (expr_list:REG_UNUSED (reg:CC 17 flags)
                    (expr_list:REG_UNUSED (reg/f:SI 68 [ suffix ])
                        (expr_list:REG_EQUAL (unspec:SI [
                                    (mem:BLK (reg/v/f:SI 63 [ suffix ]) [0 A8])
                                    (reg:QI 0 ax [70])
                                    (const_int 1 [0x1])
                                    (reg:SI 2 cx [69])
                                ] 20)
                            (nil))))))))

In fact, here is a test case which demonstrates the problem; compile it on x86 with -O3,using gcc 4.2.1, 4.0.3 or 3.4.6 (I tested them all):

#include <stdlib.h>
#include <string.h>

register long foo asm("esi");
register long bar asm("edi");

char * crash_me_baby(char *str) {
        char *path = malloc(1 + strlen(str));
        return path;
}

I’m sick and tired of the gcc team’s total unwillingness to support basic, documented, features. In this case, it is the global register variables which trigger the bug. However, the crash_me_baby() function does not use these variables at all, and in any case they are non-volatile registers which need to be saved/restored, so why the hell would it break gcc?

I submitted a bug to the gcc team. But I’m not holding my breath; I’ve already filed a report about the same issue a few years ago. This is a recurring problem which has been coming and going since the days of gcc 3.3.

The real way forward is to stop using register global variables. When the Factor VM no longer includes an interpreter, and all quotations are compiled, this will be possible without adversely affecting performance. It will also have the side benefit of making the Factor VM pure ANSI C, with some inline assembly. Which means that on Windows for example, we should soon be able to compile Factor with an alternative compiler, such as Microsoft’s Visual Studio.

For now, I’ve found a workaround – I had to write my own version of strlen().