mirror of
git://repo.or.cz/tinycc.git
synced 2026-07-03 01:48:41 +08:00
Compare commits
11 Commits
98765e5ebc
...
b39da9f6fa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b39da9f6fa | ||
|
|
5675177b7f | ||
|
|
543d84c668 | ||
|
|
9b8765d8ba | ||
|
|
7b92d2dcd2 | ||
|
|
169628a6ab | ||
|
|
8ecfd0a722 | ||
|
|
690fb14015 | ||
|
|
d5ecb52a71 | ||
|
|
6547ea47d6 | ||
|
|
898f496dc9 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -62,6 +62,7 @@ tests/*-cc*
|
|||||||
tests/*-tcc*
|
tests/*-tcc*
|
||||||
tests/libtcc_test
|
tests/libtcc_test
|
||||||
tests/libtcc_test_mt
|
tests/libtcc_test_mt
|
||||||
|
tests/libtcc_test_xor_rex
|
||||||
tests/asm-c-connect
|
tests/asm-c-connect
|
||||||
tests/asm-c-connect-sep
|
tests/asm-c-connect-sep
|
||||||
tests/vla_test
|
tests/vla_test
|
||||||
|
|||||||
@ -53,6 +53,7 @@
|
|||||||
Christian Jullien YES Windows Cygwin build and tests
|
Christian Jullien YES Windows Cygwin build and tests
|
||||||
Reimar Döffinger YES
|
Reimar Döffinger YES
|
||||||
noneofyourbusiness YES
|
noneofyourbusiness YES
|
||||||
|
Cyan Ogilvie YES
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|||||||
@ -100,7 +100,7 @@ typedef struct {
|
|||||||
__val; })
|
__val; })
|
||||||
#define atomic_load_explicit(object, order) \
|
#define atomic_load_explicit(object, order) \
|
||||||
({ __typeof__ (object) ptr = (object); \
|
({ __typeof__ (object) ptr = (object); \
|
||||||
__typeof__ (*ptr) tmp; \
|
__typeof__ ((void)0,*ptr) tmp; \
|
||||||
__atomic_load (ptr, &tmp, (order)); \
|
__atomic_load (ptr, &tmp, (order)); \
|
||||||
tmp; \
|
tmp; \
|
||||||
})
|
})
|
||||||
|
|||||||
4
tccasm.c
4
tccasm.c
@ -1100,7 +1100,7 @@ static void tcc_assemble_inline(TCCState *s1, const char *str, int len, int glob
|
|||||||
{
|
{
|
||||||
const int *saved_macro_ptr = macro_ptr;
|
const int *saved_macro_ptr = macro_ptr;
|
||||||
int dotid = set_idnum('.', IS_ID);
|
int dotid = set_idnum('.', IS_ID);
|
||||||
#ifndef TCC_TARGET_RISCV64
|
#if !defined(TCC_TARGET_RISCV64) && !defined(TCC_TARGET_X86_64)
|
||||||
int dolid = set_idnum('$', 0);
|
int dolid = set_idnum('$', 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1110,7 +1110,7 @@ static void tcc_assemble_inline(TCCState *s1, const char *str, int len, int glob
|
|||||||
tcc_assemble_internal(s1, 0, global);
|
tcc_assemble_internal(s1, 0, global);
|
||||||
tcc_close();
|
tcc_close();
|
||||||
|
|
||||||
#ifndef TCC_TARGET_RISCV64
|
#if !defined(TCC_TARGET_RISCV64) && !defined(TCC_TARGET_X86_64)
|
||||||
set_idnum('$', dolid);
|
set_idnum('$', dolid);
|
||||||
#endif
|
#endif
|
||||||
set_idnum('.', dotid);
|
set_idnum('.', dotid);
|
||||||
|
|||||||
5
tccpp.c
5
tccpp.c
@ -2500,12 +2500,13 @@ static void parse_number(const char *p)
|
|||||||
if (t >= b)
|
if (t >= b)
|
||||||
tcc_error("invalid digit");
|
tcc_error("invalid digit");
|
||||||
n = n * b + t;
|
n = n * b + t;
|
||||||
if (!ov)
|
if (!ov) {
|
||||||
/* detect overflow */
|
/* detect overflow */
|
||||||
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
||||||
ov = 1;
|
ov = 1;
|
||||||
else
|
else
|
||||||
n1 = n;
|
n1 = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
||||||
@ -3711,7 +3712,7 @@ ST_FUNC void preprocess_start(TCCState *s1, int filetype)
|
|||||||
s1->pack_stack[0] = 0;
|
s1->pack_stack[0] = 0;
|
||||||
s1->pack_stack_ptr = s1->pack_stack;
|
s1->pack_stack_ptr = s1->pack_stack;
|
||||||
|
|
||||||
set_idnum('$', !is_asm && s1->dollars_in_identifiers ? IS_ID : 0);
|
set_idnum('$', s1->dollars_in_identifiers ? IS_ID : 0);
|
||||||
set_idnum('.', is_asm ? IS_ID : 0);
|
set_idnum('.', is_asm ? IS_ID : 0);
|
||||||
|
|
||||||
if (!(filetype & AFF_TYPE_ASM)) {
|
if (!(filetype & AFF_TYPE_ASM)) {
|
||||||
|
|||||||
@ -13,6 +13,7 @@ TESTS = \
|
|||||||
hello-run \
|
hello-run \
|
||||||
libtest \
|
libtest \
|
||||||
libtest_mt \
|
libtest_mt \
|
||||||
|
libtest_xor_rex \
|
||||||
test3 \
|
test3 \
|
||||||
abitest \
|
abitest \
|
||||||
asm-c-connect-test \
|
asm-c-connect-test \
|
||||||
@ -40,6 +41,9 @@ endif
|
|||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||||
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
||||||
endif
|
endif
|
||||||
|
ifeq (,$(filter x86_64,$(ARCH)))
|
||||||
|
TESTS := $(filter-out libtest_xor_rex,$(TESTS))
|
||||||
|
endif
|
||||||
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
||||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
||||||
endif
|
endif
|
||||||
@ -103,6 +107,9 @@ libtcc_test$(EXESUF): libtcc_test.c
|
|||||||
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
||||||
|
|
||||||
|
libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c
|
||||||
|
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
||||||
|
|
||||||
%-dir:
|
%-dir:
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(MAKE) -k -C $*
|
$(MAKE) -k -C $*
|
||||||
|
|||||||
128
tests/libtcc_test_xor_rex.c
Normal file
128
tests/libtcc_test_xor_rex.c
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Test for x86_64 xor REX prefix bug in load() -- x86_64-gen.c
|
||||||
|
*
|
||||||
|
* Bug: when loading a 64-bit zero constant into registers r8-r15,
|
||||||
|
* load() emits:
|
||||||
|
*
|
||||||
|
* o(0xc031 + REG_VALUE(r) * 0x900); // xor r, r
|
||||||
|
*
|
||||||
|
* REG_VALUE(r) masks to (r & 7), losing bit 3, and no orex() call
|
||||||
|
* emits the REX prefix needed for extended registers.
|
||||||
|
*
|
||||||
|
* Result: r=TREG_R11(11) -> REG_VALUE=3 -> emits 31 db (xor ebx,ebx)
|
||||||
|
* Correct: should emit 45 31 db (REX.RB xor r11d,r11d)
|
||||||
|
*
|
||||||
|
* Fix:
|
||||||
|
* orex(0, r, r, 0x31);
|
||||||
|
* o(0xc0 + REG_VALUE(r) * 9);
|
||||||
|
*
|
||||||
|
* Trigger: an indirect call through a compile-time null function pointer,
|
||||||
|
* e.g. ((void(*)(void))0)(), causes gcall_or_jmp() to fall into the
|
||||||
|
* "indirect call" path which does load(TREG_R11, <constant 0>).
|
||||||
|
*
|
||||||
|
* This test compiles such code via the libtcc API, then inspects the
|
||||||
|
* generated machine code for the incorrect encoding.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined __x86_64__
|
||||||
|
#include <stdio.h>
|
||||||
|
int main(void) { printf("SKIP (x86_64 only)\n"); return 0; }
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "libtcc.h"
|
||||||
|
|
||||||
|
static void handle_error(void *opaque, const char *msg)
|
||||||
|
{
|
||||||
|
fprintf(opaque, "%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compiled via libtcc. The cast-to-null indirect call forces
|
||||||
|
* gcall_or_jmp() into its "else" branch (no VT_SYM, so the
|
||||||
|
* condition on line ~650 fails), which does:
|
||||||
|
*
|
||||||
|
* r = TREG_R11;
|
||||||
|
* load(r, vtop); // <-- buggy xor lands here
|
||||||
|
* o(0x41); o(0xff); // call/jmp *r
|
||||||
|
* o(0xd0 + REG_VALUE(r)); // r11 -> 0xd3
|
||||||
|
*
|
||||||
|
* We never execute the function (it would crash); we only
|
||||||
|
* inspect the generated bytes.
|
||||||
|
*/
|
||||||
|
static const char test_code[] =
|
||||||
|
"void test(void) {\n"
|
||||||
|
" ((void(*)(void))0)();\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
TCCState *s;
|
||||||
|
unsigned char *code;
|
||||||
|
int i;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
s = tcc_new();
|
||||||
|
if (!s) {
|
||||||
|
fprintf(stderr, "tcc_new() failed\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
tcc_set_error_func(s, stderr, handle_error);
|
||||||
|
|
||||||
|
for (i = 1; i < argc; ++i) {
|
||||||
|
char *a = argv[i];
|
||||||
|
if (a[0] == '-') {
|
||||||
|
if (a[1] == 'B')
|
||||||
|
tcc_set_lib_path(s, a + 2);
|
||||||
|
else if (a[1] == 'I')
|
||||||
|
tcc_add_include_path(s, a + 2);
|
||||||
|
else if (a[1] == 'L')
|
||||||
|
tcc_add_library_path(s, a + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||||
|
if (tcc_compile_string(s, test_code) == -1)
|
||||||
|
return 2;
|
||||||
|
if (tcc_relocate(s) < 0)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
code = (unsigned char *)tcc_get_symbol(s, "test");
|
||||||
|
if (!code) {
|
||||||
|
fprintf(stderr, "symbol 'test' not found\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan for the 'call *%r11' instruction: 41 ff d3
|
||||||
|
* Then inspect the bytes immediately before it.
|
||||||
|
*
|
||||||
|
* Correct: 45 31 db 41 ff d3 (xor %r11d,%r11d ; call *%r11)
|
||||||
|
* Buggy: 31 db 41 ff d3 (xor %ebx,%ebx ; call *%r11)
|
||||||
|
*/
|
||||||
|
for (i = 3; i < 128; i++) {
|
||||||
|
if (code[i] == 0x41 && code[i+1] == 0xff && code[i+2] == 0xd3) {
|
||||||
|
if (i >= 3 && code[i-3] == 0x45
|
||||||
|
&& code[i-2] == 0x31
|
||||||
|
&& code[i-1] == 0xdb) {
|
||||||
|
printf("xor_rex: OK\n");
|
||||||
|
} else if (i >= 2 && code[i-2] == 0x31 && code[i-1] == 0xdb) {
|
||||||
|
printf("xor_rex: FAIL - xor %%ebx,%%ebx (31 db) emitted"
|
||||||
|
" instead of xor %%r11d,%%r11d (45 31 db)\n");
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
printf("xor_rex: FAIL - unexpected bytes before"
|
||||||
|
" call *%%r11: %02x %02x %02x %02x\n",
|
||||||
|
code[i-4], code[i-3], code[i-2], code[i-1]);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("xor_rex: SKIP - call *%%r11 not found in generated code\n");
|
||||||
|
|
||||||
|
done:
|
||||||
|
tcc_delete(s);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -495,7 +495,8 @@ void load(int r, SValue *sv)
|
|||||||
orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */
|
orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */
|
||||||
gen_le32(sv->c.i);
|
gen_le32(sv->c.i);
|
||||||
} else {
|
} else {
|
||||||
o(0xc031 + REG_VALUE(r) * 0x900); /* xor r, r */
|
orex(0, r, r, 0x31); /* xor r, r */
|
||||||
|
o(0xc0 + REG_VALUE(r) * 9);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */
|
orex(0,r,0, 0xb8 + REG_VALUE(r)); /* mov $xx, r */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user