Git Product home page Git Product logo

c's Introduction

A small, fast C compiler suite.

NOTE - This project is not being actively developed. Please direct yourself to https://github.com/michaelforney/cc which is a successor that is more complete. I direct my own fixes to that project instead now.

Join the chat at https://gitter.im/andrewchambers/c

  • Small.
  • Fast.
  • Consistent.
  • High quality.
  • Low complexity.
  • No dependencies.
  • No fussy configuration.
  • Painless cross compiling.
  • Just work.

You should be able to get a C compiler, assembler, linker and libc for any supported target in less than 30 seconds.

Building

Requires an external C compiler and gnu binutils (for now), and I have only tested it on linux 64 bit so far.

The code does use anonymous union extensions, so your compiler will need to support them too.

$ make

Testing

$ make test
$ make selfhost # self hosting

Plan

Stage 1.

Self hosting x86_64, dumb backend.

Stage 2.

Self hosting arm, something like raspberry pi/android.

Stage 3.

Build small clean C code bases like 8cc, tcc, sbase.

Stage 4.

Build musl libc.

Beyond.

  • Build more programs.
  • Replace gnu as with our own assembler.
  • Replace ld with our own static linker.
  • Build OS kernels.
  • SSA backend.

Status

Pre stage 2. Self hosting with lots of missing common cases. Though technically these bugs can be fixed with the compiler itself :). It uses it's own stubbed out headers and cannot correctly process system headers yet (Help wanted).

Contributing

Project on hold. See https://github.com/michaelforney/cc for a new compiler project that is more complete.

Code layout

  • Libraries are in src/*
  • Commands are in src/cmd/*

If you are unsure about the purpose of a library, check the header which should give a short description.

Code style

Follow Plan9 style conventions. Headers are not allowed to include other headers to eliminate circular dependencies and increase build speed. src/u.h is the only exception to this rule.

Bug fixes and issues

Try and attach a single source file which exibits your issue. If possible reduce the test case by hand until it is as small as possible.

Try and follow the general template changed where needed:

What are you trying to do:
...
What you expected to happen:
...
What actually hapened:
...

Try and add a small self contained file which reproduces the issue.

In general each bug fix or change should add a test file which triggers the bug.

Memory management

The compiler does not explicitly free memory. Peak memory usage while self hosting is approximately 2Mb, so it should not be an issue, even for planned targets/hosts like the raspberry pi.

This actually simplifies the code and probably makes it faster because allocations can be pointer bumps.

Useful Links

c's People

Contributors

andrewchambers avatar f2404 avatar k0gamsx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

c's Issues

amd64 backend reminder

(0xffffffff + 1) == 0;
We currently fail this test because we are extending all values. Comparisions and Bool checking need to take size into account.

stack alignment is incorrect

Hey, it seems that the stack pointer is not correctly set to 0 mod 16 at call boundaries. The following example triggers a segfault on my machine.

int printf(char *, ...);
int *calloc(int, int);

int N;
int *t;

print() {
        int x;
        int y;

        for (y=0; y<8; y++) {
                for (x=0; x<8; x++)
                        if (t[x + 8*y])
                                printf(" Q");
                        else
                                printf(" .");
                printf("\n");
        }
        printf("\n");
}

chk(int x, int y) {
        int i;
        int r;

        for (r=i=0; i<8; i++) {
                r = r + t[x + 8*i];
                r = r + t[i + 8*y];
                if (x+i < 8 & y+i < 8)
                        r = r + t[x+i + 8*(y+i)];
                if (x+i < 8 & y-i >= 0)
                        r = r + t[x+i + 8*(y-i)];
                if (x-i >= 0 & y+i < 8)
                        r = r + t[x-i + 8*(y+i)];
                if (x-i >= 0 & y-i >= 0)
                        r = r + t[x-i + 8*(y-i)];
        }
        return r;
}

go(int n, int x, int y) {
        if (n == 8) {
                print();
                N++;
                return 0;
        }
        for (; y<8; y++) {
                for (; x<8; x++)
                        if (chk(x, y) == 0) {
                                t[x + 8*y]++;
                                go(n+1, x, y);
                                t[x + 8*y]--;
                        }
                x = 0;
        }
}

main() {
        t = calloc(64, sizeof(int));
        go(0, 0, 0);
        printf("found %d solutions\n", N);
}

Small mistake in code

In the following piece of code I think you meant to write if(c >= 'A' && c <= 'F').

hexnumberc(int c)
{
    if(numberc(c))
        return 1;
    if(c >= 'a' && c <= 'f')
        return 1;
    if(c >= 'F' && c <= 'F')
        return 1;
    return 0;
}

Return register breaks with integer params in 6c

struct s0 {
    long m0;
    long m1;
};
struct s1 {
    struct s0 m0;
    long m1;
};
struct s2 {
    int m0;
};
void abort(void);
struct s1
f(int p0, struct s2 p1)
{
    struct s1 r;
    r.m0.m0 = 1293431308;
    r.m0.m1 = 61651767;
    r.m1 = 1736112203;
    if(p0 != 413324820) abort();
    if(p1.m0 != 1141848071) abort();
    return r;
}
int
main()
{
    struct s1 r;
    int p0;
    struct s2 p1;
    p0 = 413324820;
    p1.m0 = 1141848071;
    r = f(p0, p1);
    if(r.m0.m0 != 1293431308) abort();
    if(r.m0.m1 != 61651767) abort();
    if(r.m1 != 1736112203) abort();
    return 0;
}

Valgrind issue

Running the compiler on amd64 ubuntu I get the following valgrind report. Is this a false positive?

andrew@blackheart:~/src/c$ valgrind bin/6c test/execute/0001-sanity.c
==3118== Memcheck, a memory error detector
==3118== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3118== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==3118== Command: bin/6c test/execute/0001-sanity.c
==3118== 
==3118== Conditional jump or move depends on uninitialised value(s)
==3118==    at 0x4540D6: __linkin_atfork (in /home/andrew/src/c/bin/6c)
==3118==    by 0x42CDA3: ptmalloc_init.part.7 (in /home/andrew/src/c/bin/6c)
==3118==    by 0x42D1F4: malloc_hook_ini (in /home/andrew/src/c/bin/6c)
==3118==    by 0x47AA3A: _dl_get_origin (in /home/andrew/src/c/bin/6c)
==3118==    by 0x45499E: _dl_non_dynamic_init (in /home/andrew/src/c/bin/6c)
==3118==    by 0x455797: __libc_init_first (in /home/andrew/src/c/bin/6c)
==3118==    by 0x409B3B: (below main) (in /home/andrew/src/c/bin/6c)
...

pool allocator

We can get most of the benefits of not doing manual memory management, but allow compilation of multiple files by using a pool allocator and freeing the pools at the end of each .c file.

Array check of sametype function has an error

types.c
case CARR: if(r->t != CARR) return 0; if(r->Arr.dim != l->Arr.dim) return 0; + if(!sametype(l->Arr.subty, r->Arr.subty)) + return 0; return 1;
The old version did not check the subtype of the array.

Project euler example miscompiled.


int
main()
{
    int i, n, p, next, isprime;

    n = 5;
    p = 11;
    next = 12;
    while(n != 100) {
        isprime = 1;
        if(next % 2 == 0) {
            isprime = 0;
        } else {
            for(i = 3; i < next; i = i + 2) {
                if(next % i == 0) {
                    isprime = 0;
                    break;
                }
            }
        }
        if(isprime) {
            p = next;
            n++;
        }
        next = next + 1;
    }
    if(p != 541)
        return 1;
    return 0;
}

error make test

on arml6

$make test
make clean
make[1]: Wejście do katalogu '/home/user/inne/c'
rm -rf src/panic.o src/cc/cpp.o src/cc/lex.o src/cc/parse.o src/cc/types.o src/cc/foldexpr.o src/cc/error.o src/mem/mem.o src/ds/list.o src/ds/map.o src/ds/vec.o src/ds/strset.o src/cmd/cpp/main.o src/cmd/6c/emit.o src/cmd/6c/frontend.o src/cmd/6c/main.o src/cmd/abifuzz/main.o lib bin
make[1]: Opuszczenie katalogu '/home/user/inne/c'
make all
make[1]: Wejście do katalogu '/home/user/inne/c'
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cmd/6c/emit.o -c src/cmd/6c/emit.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cmd/6c/frontend.o -c src/cmd/6c/frontend.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cmd/6c/main.o -c src/cmd/6c/main.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/panic.o -c src/panic.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/cpp.o -c src/cc/cpp.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/lex.o -c src/cc/lex.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/parse.o -c src/cc/parse.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/types.o -c src/cc/types.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/foldexpr.o -c src/cc/foldexpr.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cc/error.o -c src/cc/error.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/mem/mem.o -c src/mem/mem.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/ds/list.o -c src/ds/list.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/ds/map.o -c src/ds/map.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/ds/vec.o -c src/ds/vec.c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/ds/strset.o -c src/ds/strset.c
ar rcs lib/libcompiler.a src/panic.o src/cc/cpp.o src/cc/lex.o src/cc/parse.o src/cc/types.o src/cc/foldexpr.o src/cc/error.o src/mem/mem.o src/ds/list.o src/ds/map.o src/ds/vec.o src/ds/strset.o
cc src/cmd/6c/emit.o src/cmd/6c/frontend.o src/cmd/6c/main.o lib/libcompiler.a -o bin/6c
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cmd/cpp/main.o -c src/cmd/cpp/main.c
cc src/cmd/cpp/main.o lib/libcompiler.a -o bin/cpp
cc -std=c89 -g -Wfatal-errors -Wno-unused-parameter -Wall -Wextra -D_DEFAULT_SOURCE -Isrc/ -o src/cmd/abifuzz/main.o -c src/cmd/abifuzz/main.c
cc src/cmd/abifuzz/main.o lib/libcompiler.a -o bin/abifuzz
make[1]: Opuszczenie katalogu '/home/user/inne/c'
./test.sh
test/execute/0001-sanity.c.s: Assembler messages:
test/execute/0001-sanity.c.s:7: Error: bad instruction pushq %rbp' test/execute/0001-sanity.c.s:8: Error: bad instruction movq %rsp,%rbp'
test/execute/0001-sanity.c.s:9: Error: bad instruction movq $0,%rax' test/execute/0001-sanity.c.s:10: Error: bad instruction leave'
test/execute/0001-sanity.c.s:11: Error: bad instruction ret' test/execute/0001-sanity.c.s:12: Error: bad instruction leave'
test/execute/0001-sanity.c.s:13: Error: bad instruction `ret'
test/execute/0001-sanity.c FAIL
Makefile:31: polecenia dla obiektu 'test' nie powiodły się
make: *** [test] Błąd 1

$uname -a
Linux 4.14.98+ #1200 Tue Feb 12 20:11:02 GMT 2019 armv6l GNU/Linux
$make no errors

Create fuzzer for struct calls.

We should fuzz our abi implementation by generating random structs and random function definitions and calling back and forth from gcc/clang compiled code.

refactor lexer

The lexer has become one of the ugliest parts of the code. At the very least number, ident, comment and whitespace processing can be put in dedicated functions.

How do you feel about constexpr in C23?

WG14 is considering adding constexpr to C23, they're worried it may kill single pass, no AST compilers from working, and it looks like yours fits that description.

what are your thoughts?

Bug!

$ make test

...
...
test/bugs/0004.c PASS
test/bugs/0005.c PASS
test/bugs/0006.c PASS
test/bugs/0008.c PASS
/usr/bin/ld: test/bugs/0012.c.o: relocation R_X86_64_PC32 against symbol `abort@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
test/bugs/0012.c FAIL
Makefile:31: recipe for target 'test' failed
make: *** [test] Error 1

how fix?!

miscompile

a;
abort();
main() {
  int b = 1080377166;
  long c = a;
  if (b != 1080377166)
    abort();
}

found with abifuzz and creduce

Can I use this to make a scripting language?

Hello Andrew, I'm Nergal and I'm interesting in forking over this C compiler suite to create a game scripting language. May I have permission? Also, how stable is this compiler suite?

There is an bug in the foldbinop function

Should be:
case '+': if(l->p && r->p) return 0; if(l->p) + return mkconst(l->p, l->v + r->v); if(r->p) + return mkconst(r->p, l->v + r->v); return mkconst(0, l->v + r->v);

frontend

Is possible to create my own frontend?
for example bison or ragel grammar

miscompilation

struct s {
    char a;
    char b;
};

void abort(void);

struct s
f()
{
    struct s r;
    r.a = 1;
    r.b = 2;
    return r;
}
int
main()
{
    struct s r;
    r = f();
    if(r.a != 1) abort();
    if(r.b != 2) abort();
    return 0;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.