Skip to content

Commit 95ad79f

Browse files
committed
Support Windows x64 calling convention
- Can somewhat-parse MSVC runtime and common Windows SDK CRT headers (but windows.h not attempted yet). Some important things are ignored though, notably pragma pack and all __declspecs. - All self-tests pass for both calling convention styles. - Calls of integer, floating, struct pass/return work, as do varargs, using the stdargs.h/vadefs.h style of MSVC for compatibility. - Ported from clang/gcc-reliant C11 to MSVC's flavour of somewhat annoying C99-ish. - Updated test code to deal with sizeof(long) == 4 on Windows. - long double are passed around as 8 byte as per Windows and treated as (8 byte) doubles rather than 16 and using the x87 stack as on SysV. I'm not totally sure if this matches MSVC or not, but I don't have a lot of use for long double. - .pdata/.xdata RUNTIME_FUNCTIONs are not yet generated and registered, that will a subsequent change.
1 parent 4fc87b8 commit 95ad79f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1486
-521
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ tags
1313
objconv.exe
1414
test/x.c
1515
minilua
16-
codegen.c
16+
codegen.linux.c
17+
codegen.win32.c

Makefile

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,10 @@
1-
CFLAGS=-std=c11 -g -fno-common -Wall -Werror -Wno-switch -pthread -Wunreachable-code -Wmisleading-indentation
1+
include makefile.shared
22

3-
SRCS=codegen.c hashmap.c main.c parse.c preprocess.c strings.c tokenize.c type.c unicode.c alloc.c dyo.c link.c
4-
OBJS=$(SRCS:.c=.o)
3+
CFLAGS=-std=c11 -g -fno-common -Wall -Werror -Wno-switch -pthread
4+
5+
SRCS += codegen.linux.c
56

6-
# XXX:
7-
# test/asm.c
8-
# dyibicc passes asm() blocks directly through to the system assembler, so now
9-
# that we're not using that, there's no assembler available.
10-
#
11-
# test/tls.c
12-
# TLS not implemented
13-
#
14-
# test/commonsym.c
15-
# currently passes, but I thought I disabled support, so need to investigate.
16-
#
17-
TEST_SRCS=\
18-
test/alignof.c \
19-
test/alloca.c \
20-
test/arith.c \
21-
test/atomic.c \
22-
test/attribute.c \
23-
test/bitfield.c \
24-
test/builtin.c \
25-
test/cast.c \
26-
test/commonsym.c \
27-
test/compat.c \
28-
test/complit.c \
29-
test/const.c \
30-
test/constexpr.c \
31-
test/control.c \
32-
test/decl.c \
33-
test/enum.c \
34-
test/extern.c \
35-
test/float.c \
36-
test/function.c \
37-
test/generic.c \
38-
test/initializer.c \
39-
test/line.c \
40-
test/literal.c \
41-
test/macro.c \
42-
test/offsetof.c \
43-
test/pointer.c \
44-
test/pragma-once.c \
45-
test/sizeof.c \
46-
test/stdhdr.c \
47-
test/string.c \
48-
test/struct.c \
49-
test/typedef.c \
50-
test/typeof.c \
51-
test/usualconv.c \
52-
test/unicode.c \
53-
test/union.c \
54-
test/varargs.c \
55-
test/variable.c \
56-
test/vla.c
7+
OBJS=$(SRCS:.c=.o)
578

589
dyibicc: $(OBJS)
5910
$(CC) $(CFLAGS) -o $@ $^ -ldl $(LDFLAGS)
@@ -66,7 +17,7 @@ $(OBJS): dyibicc.h
6617
minilua: dynasm/minilua.c
6718
$(CC) $(CFLAGS) -o $@ $^ -lm
6819

69-
codegen.c: codegen.in.c minilua
20+
codegen.linux.c: codegen.in.c minilua
7021
./minilua dynasm/dynasm.lua -o $@ codegen.in.c
7122

7223
test: $(TEST_SRCS) dyibicc
@@ -75,8 +26,8 @@ test: $(TEST_SRCS) dyibicc
7526
# Misc.
7627

7728
clean:
78-
rm -rf dyibicc dumpdyo codegen.c tmp* test/*.s test/*.exe minilua minilua.exe *.dyo *.exe *.pdb *.ilk
29+
rm -rf dyibicc dumpdyo codegen.c test/*.s test/*.exe minilua minilua.exe *.dyo *.exe *.pdb *.ilk
7930
find * -type f '(' -name '*~' -o -name '*.o' ')' -exec rm {} ';'
8031
clang-format -i *.c *.h
8132

82-
.PHONY: test clean test-stage2 dumpdyo
33+
.PHONY: test clean

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@ generates machine code via [DynASM](https://luajit.org/dynasm.html).
66
I renamed it from chibicc to dyibicc to avoid confusion between the two. But the
77
code still overwhelmingly follows Rui's model and style.
88

9-
Build and test with:
9+
Build and test on Linux with:
1010

1111
```
1212
$ make
1313
$ make test
1414
```
1515

16-
Currently only supports Linux and x64. (It will build on Windows where it can
17-
generate .dyos, but the calling convention is always SysV so they can't be run.)
16+
or on Windows (from a VS x64 cmd):
17+
18+
```
19+
> make
20+
> make test
21+
```
22+
23+
Currently only supports Linux or Windows, and x64 only.

alloc.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,36 @@
11
#include "dyibicc.h"
22

3-
#ifdef _MSC_VER
3+
#if X64WIN
44
#include <windows.h>
55
#else
66
#include <sys/mman.h>
77
#endif
88

9-
static void* allmem;
10-
static void* current_alloc_pointer;
9+
static char* allmem;
10+
static char* current_alloc_pointer;
1111

1212
#define HEAP_SIZE (256 << 20)
1313

14+
// Reports an error and exit.
15+
void error(char* fmt, ...) {
16+
va_list ap;
17+
va_start(ap, fmt);
18+
vfprintf(stderr, fmt, ap);
19+
fprintf(stderr, "\n");
20+
exit(1);
21+
}
22+
1423
void bumpcalloc_init(void) {
1524
allmem = allocate_writable_memory(HEAP_SIZE);
1625
current_alloc_pointer = allmem;
1726
}
1827

1928
void* bumpcalloc(size_t num, size_t size) {
20-
size_t toalloc = align_to(num * size, 8);
21-
void* ret = current_alloc_pointer;
29+
size_t toalloc = align_to((int)(num * size), 8);
30+
char* ret = current_alloc_pointer;
2231
current_alloc_pointer += toalloc;
2332
if (current_alloc_pointer > allmem + HEAP_SIZE) {
24-
fprintf(stderr, "heap exhausted");
25-
abort();
33+
error("heap exhausted");
2634
}
2735
memset(ret, 0, toalloc);
2836
return ret;
@@ -41,7 +49,7 @@ void bumpcalloc_reset(void) {
4149
}
4250

4351
void* aligned_allocate(size_t size, size_t alignment) {
44-
#ifdef _MSC_VER
52+
#if X64WIN
4553
return _aligned_malloc(size, alignment);
4654
#else
4755
return aligned_alloc(alignment, size);
@@ -52,11 +60,10 @@ void* aligned_allocate(size_t size, size_t alignment) {
5260
// prints out the error and returns NULL. Unlike malloc, the memory is allocated
5361
// on a page boundary so it's suitable for calling mprotect.
5462
void* allocate_writable_memory(size_t size) {
55-
#ifdef _MSC_VER
63+
#if X64WIN
5664
void* p = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
5765
if (!p) {
58-
fprintf(stderr, "VirtualAlloc failed");
59-
return NULL;
66+
error("VirtualAlloc failed: 0x%x\n", GetLastError());
6067
}
6168
return p;
6269
#else
@@ -72,7 +79,9 @@ void* allocate_writable_memory(size_t size) {
7279
// Sets a RX permission on the given memory, which must be page-aligned. Returns
7380
// 0 on success. On failure, prints out the error and returns -1.
7481
bool make_memory_executable(void* m, size_t size) {
75-
#ifdef _MSC_VER
82+
#if X64WIN
83+
(void)m;
84+
(void)size;
7685
// TODO: alloc as non-execute
7786
return true;
7887
#else
@@ -85,7 +94,7 @@ bool make_memory_executable(void* m, size_t size) {
8594
}
8695

8796
void free_executable_memory(void* p, size_t size) {
88-
#ifdef _MSC_VER
97+
#if X64WIN
8998
VirtualFree(p, size, MEM_RELEASE);
9099
#else
91100
munmap(p, size);

0 commit comments

Comments
 (0)