mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-27 06:10:06 +08:00
tccgen/win32: let __declspec(dllimport) imply extern
Also, retain storage qualifiers in type_decl, in particular also for function pointers. This allows to get rid of this very early hack in decl() type.t |= (btype.t & VT_STATIC); /* Retain "static". */ which was to fix the case of int main() { static int (*foo)(); ... Also: - missing __declspec(dllimport) is an error now - except if the symbol is "_imp__symbol" - demonstrate export/import of data in the dll example (while 'extern' isn't strictly required with dllimport anymore) - new function 'patch_storage()' replaces 'weaken_symbol()' and 'apply_visibility()' - new function 'update_storage()' applies storage attributes to Elf symbols. - put_extern_sym/2 accepts new pseudo section SECTION_COMMON - add -Wl,-export-all-symbols as alias for -rdynamic - add -Wl,-subsystem=windows for mingw compatibility - redefinition of 'sym' error for initialized global data
This commit is contained in:
parent
c4c3f5009e
commit
536ed76d5a
6
libtcc.c
6
libtcc.c
@ -1299,6 +1299,8 @@ static int link_option(const char *str, const char *val, const char **ptr)
|
|||||||
if (*p != ',' && *p != '=')
|
if (*p != ',' && *p != '=')
|
||||||
return 0;
|
return 0;
|
||||||
p++;
|
p++;
|
||||||
|
} else if (*p) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
*ptr = p;
|
*ptr = p;
|
||||||
return ret;
|
return ret;
|
||||||
@ -1369,6 +1371,8 @@ static int tcc_set_linker(TCCState *s, const char *option)
|
|||||||
ignoring = 1;
|
ignoring = 1;
|
||||||
} else if (link_option(option, "O", &p)) {
|
} else if (link_option(option, "O", &p)) {
|
||||||
ignoring = 1;
|
ignoring = 1;
|
||||||
|
} else if (link_option(option, "export-all-symbols", &p)) {
|
||||||
|
s->rdynamic = 1;
|
||||||
} else if (link_option(option, "rpath=", &p)) {
|
} else if (link_option(option, "rpath=", &p)) {
|
||||||
copy_linker_arg(&s->rpath, p, ':');
|
copy_linker_arg(&s->rpath, p, ':');
|
||||||
} else if (link_option(option, "enable-new-dtags", &p)) {
|
} else if (link_option(option, "enable-new-dtags", &p)) {
|
||||||
@ -1390,7 +1394,7 @@ static int tcc_set_linker(TCCState *s, const char *option)
|
|||||||
s->pe_subsystem = 1;
|
s->pe_subsystem = 1;
|
||||||
} else if (!strcmp(p, "console")) {
|
} else if (!strcmp(p, "console")) {
|
||||||
s->pe_subsystem = 3;
|
s->pe_subsystem = 3;
|
||||||
} else if (!strcmp(p, "gui")) {
|
} else if (!strcmp(p, "gui") || !strcmp(p, "windows")) {
|
||||||
s->pe_subsystem = 2;
|
s->pe_subsystem = 2;
|
||||||
} else if (!strcmp(p, "posix")) {
|
} else if (!strcmp(p, "posix")) {
|
||||||
s->pe_subsystem = 7;
|
s->pe_subsystem = 7;
|
||||||
|
3
tcc.c
3
tcc.c
@ -117,13 +117,14 @@ static const char help2[] =
|
|||||||
"-Wl,... linker options:\n"
|
"-Wl,... linker options:\n"
|
||||||
" -nostdlib do not link with standard crt/libs\n"
|
" -nostdlib do not link with standard crt/libs\n"
|
||||||
" -[no-]whole-archive load lib(s) fully/only as needed\n"
|
" -[no-]whole-archive load lib(s) fully/only as needed\n"
|
||||||
|
" -export-all-symbols same as -rdynamic\n"
|
||||||
" -image-base= -Ttext= set base address of executable\n"
|
" -image-base= -Ttext= set base address of executable\n"
|
||||||
" -section-alignment= set section alignment in executable\n"
|
" -section-alignment= set section alignment in executable\n"
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
" -file-alignment= set PE file alignment\n"
|
" -file-alignment= set PE file alignment\n"
|
||||||
" -stack= set PE stack reserve\n"
|
" -stack= set PE stack reserve\n"
|
||||||
" -large-address-aware set related PE option\n"
|
" -large-address-aware set related PE option\n"
|
||||||
" -subsystem=[console gui] set PE subsystem\n"
|
" -subsystem=[console/windows] set PE subsystem\n"
|
||||||
" -oformat=[pe-* binary] set executable output format\n"
|
" -oformat=[pe-* binary] set executable output format\n"
|
||||||
"Predefined macros:\n"
|
"Predefined macros:\n"
|
||||||
" tcc -E -dM - < nul\n"
|
" tcc -E -dM - < nul\n"
|
||||||
|
1
tcc.h
1
tcc.h
@ -458,6 +458,7 @@ typedef struct Sym {
|
|||||||
|
|
||||||
/* special flag, too */
|
/* special flag, too */
|
||||||
#define SECTION_ABS ((void *)1)
|
#define SECTION_ABS ((void *)1)
|
||||||
|
#define SECTION_COMMON ((void *)2)
|
||||||
|
|
||||||
typedef struct Section {
|
typedef struct Section {
|
||||||
unsigned long data_offset; /* current data offset */
|
unsigned long data_offset; /* current data offset */
|
||||||
|
261
tccgen.c
261
tccgen.c
@ -258,6 +258,33 @@ ST_FUNC void tccgen_end(TCCState *s1)
|
|||||||
tcc_debug_end(s1);
|
tcc_debug_end(s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* apply storage attibutes to Elf symbol */
|
||||||
|
|
||||||
|
static void update_storage(Sym *sym)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
|
||||||
|
if (0 == sym->c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
t = sym->type.t;
|
||||||
|
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
||||||
|
|
||||||
|
if (t & VT_VIS_MASK)
|
||||||
|
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
|
||||||
|
| ((t & VT_VIS_MASK) >> VT_VIS_SHIFT);
|
||||||
|
|
||||||
|
if (t & VT_WEAK)
|
||||||
|
esym->st_info = ELFW(ST_INFO)(STB_WEAK, ELFW(ST_TYPE)(esym->st_info));
|
||||||
|
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
if (t & VT_EXPORT)
|
||||||
|
esym->st_other |= ST_PE_EXPORT;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* update sym->c so that it points to an external symbol in section
|
/* update sym->c so that it points to an external symbol in section
|
||||||
'section' with value 'value' */
|
'section' with value 'value' */
|
||||||
@ -266,11 +293,10 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
|
|||||||
addr_t value, unsigned long size,
|
addr_t value, unsigned long size,
|
||||||
int can_add_underscore)
|
int can_add_underscore)
|
||||||
{
|
{
|
||||||
int sym_type, sym_bind, sh_num, info, other;
|
int sym_type, sym_bind, sh_num, info, other, t;
|
||||||
ElfW(Sym) *esym;
|
ElfW(Sym) *esym;
|
||||||
const char *name;
|
const char *name;
|
||||||
char buf1[256];
|
char buf1[256];
|
||||||
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
char buf[32];
|
char buf[32];
|
||||||
#endif
|
#endif
|
||||||
@ -279,26 +305,11 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
|
|||||||
sh_num = SHN_UNDEF;
|
sh_num = SHN_UNDEF;
|
||||||
else if (section == SECTION_ABS)
|
else if (section == SECTION_ABS)
|
||||||
sh_num = SHN_ABS;
|
sh_num = SHN_ABS;
|
||||||
|
else if (section == SECTION_COMMON)
|
||||||
|
sh_num = SHN_COMMON;
|
||||||
else
|
else
|
||||||
sh_num = section->sh_num;
|
sh_num = section->sh_num;
|
||||||
|
|
||||||
if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
|
|
||||||
sym_type = STT_FUNC;
|
|
||||||
} else if ((sym->type.t & VT_BTYPE) == VT_VOID) {
|
|
||||||
sym_type = STT_NOTYPE;
|
|
||||||
} else {
|
|
||||||
sym_type = STT_OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sym->type.t & VT_STATIC)
|
|
||||||
sym_bind = STB_LOCAL;
|
|
||||||
else {
|
|
||||||
if (sym->type.t & VT_WEAK)
|
|
||||||
sym_bind = STB_WEAK;
|
|
||||||
else
|
|
||||||
sym_bind = STB_GLOBAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sym->c) {
|
if (!sym->c) {
|
||||||
name = get_tok_str(sym->v, NULL);
|
name = get_tok_str(sym->v, NULL);
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
@ -328,39 +339,39 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
t = sym->type.t;
|
||||||
|
if ((t & VT_BTYPE) == VT_FUNC) {
|
||||||
|
sym_type = STT_FUNC;
|
||||||
|
} else if ((t & VT_BTYPE) == VT_VOID) {
|
||||||
|
sym_type = STT_NOTYPE;
|
||||||
|
} else {
|
||||||
|
sym_type = STT_OBJECT;
|
||||||
|
}
|
||||||
|
if (t & VT_STATIC)
|
||||||
|
sym_bind = STB_LOCAL;
|
||||||
|
else
|
||||||
|
sym_bind = STB_GLOBAL;
|
||||||
other = 0;
|
other = 0;
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
if (sym->type.t & VT_EXPORT)
|
|
||||||
other |= ST_PE_EXPORT;
|
|
||||||
if (sym_type == STT_FUNC && sym->type.ref) {
|
if (sym_type == STT_FUNC && sym->type.ref) {
|
||||||
Sym *ref = sym->type.ref;
|
Sym *ref = sym->type.ref;
|
||||||
if (ref->a.func_export)
|
|
||||||
other |= ST_PE_EXPORT;
|
|
||||||
if (ref->a.func_call == FUNC_STDCALL && can_add_underscore) {
|
if (ref->a.func_call == FUNC_STDCALL && can_add_underscore) {
|
||||||
sprintf(buf1, "_%s@%d", name, ref->a.func_args * PTR_SIZE);
|
sprintf(buf1, "_%s@%d", name, ref->a.func_args * PTR_SIZE);
|
||||||
name = buf1;
|
name = buf1;
|
||||||
other |= ST_PE_STDCALL;
|
other |= ST_PE_STDCALL;
|
||||||
can_add_underscore = 0;
|
can_add_underscore = 0;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (find_elf_sym(tcc_state->dynsymtab_section, name))
|
|
||||||
other |= ST_PE_IMPORT;
|
|
||||||
if (sym->type.t & VT_IMPORT)
|
|
||||||
other |= ST_PE_IMPORT;
|
|
||||||
}
|
}
|
||||||
#else
|
if (t & VT_IMPORT)
|
||||||
if (! (sym->type.t & VT_STATIC))
|
other |= ST_PE_IMPORT;
|
||||||
other = (sym->type.t & VT_VIS_MASK) >> VT_VIS_SHIFT;
|
|
||||||
#endif
|
#endif
|
||||||
if (tcc_state->leading_underscore && can_add_underscore) {
|
if (tcc_state->leading_underscore && can_add_underscore) {
|
||||||
buf1[0] = '_';
|
buf1[0] = '_';
|
||||||
pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
|
pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
|
||||||
name = buf1;
|
name = buf1;
|
||||||
}
|
}
|
||||||
if (sym->asm_label) {
|
if (sym->asm_label)
|
||||||
name = get_tok_str(sym->asm_label, NULL);
|
name = get_tok_str(sym->asm_label, NULL);
|
||||||
}
|
|
||||||
info = ELFW(ST_INFO)(sym_bind, sym_type);
|
info = ELFW(ST_INFO)(sym_bind, sym_type);
|
||||||
sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name);
|
sym->c = set_elf_sym(symtab_section, value, size, info, other, sh_num, name);
|
||||||
} else {
|
} else {
|
||||||
@ -369,6 +380,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
|
|||||||
esym->st_size = size;
|
esym->st_size = size;
|
||||||
esym->st_shndx = sh_num;
|
esym->st_shndx = sh_num;
|
||||||
}
|
}
|
||||||
|
update_storage(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
|
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
|
||||||
@ -580,41 +592,6 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
|
|||||||
*ptop = b;
|
*ptop = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void weaken_symbol(Sym *sym)
|
|
||||||
{
|
|
||||||
sym->type.t |= VT_WEAK;
|
|
||||||
if (sym->c > 0) {
|
|
||||||
int esym_type;
|
|
||||||
ElfW(Sym) *esym;
|
|
||||||
|
|
||||||
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
|
||||||
esym_type = ELFW(ST_TYPE)(esym->st_info);
|
|
||||||
esym->st_info = ELFW(ST_INFO)(STB_WEAK, esym_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void apply_visibility(Sym *sym, CType *type)
|
|
||||||
{
|
|
||||||
int vis = sym->type.t & VT_VIS_MASK;
|
|
||||||
int vis2 = type->t & VT_VIS_MASK;
|
|
||||||
if (vis == (STV_DEFAULT << VT_VIS_SHIFT))
|
|
||||||
vis = vis2;
|
|
||||||
else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT))
|
|
||||||
;
|
|
||||||
else
|
|
||||||
vis = (vis < vis2) ? vis : vis2;
|
|
||||||
sym->type.t &= ~VT_VIS_MASK;
|
|
||||||
sym->type.t |= vis;
|
|
||||||
|
|
||||||
if (sym->c > 0) {
|
|
||||||
ElfW(Sym) *esym;
|
|
||||||
|
|
||||||
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
|
||||||
vis >>= VT_VIS_SHIFT;
|
|
||||||
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void vsetc(CType *type, int r, CValue *vc)
|
static void vsetc(CType *type, int r, CValue *vc)
|
||||||
@ -831,31 +808,49 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Merge some storage attributes. */
|
||||||
|
static void patch_storage(Sym *sym, CType *type)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
if (!is_compatible_types(&sym->type, type))
|
||||||
|
tcc_error("incompatible types for redefinition of '%s'",
|
||||||
|
get_tok_str(sym->v, NULL));
|
||||||
|
t = type->t;
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
if ((sym->type.t ^ t) & VT_IMPORT)
|
||||||
|
tcc_error("incompatible dll linkage for redefinition of '%s'",
|
||||||
|
get_tok_str(sym->v, NULL));
|
||||||
|
#endif
|
||||||
|
sym->type.t |= t & (VT_EXPORT|VT_WEAK);
|
||||||
|
if (t & VT_VIS_MASK) {
|
||||||
|
int vis = sym->type.t & VT_VIS_MASK;
|
||||||
|
int vis2 = t & VT_VIS_MASK;
|
||||||
|
if (vis == (STV_DEFAULT << VT_VIS_SHIFT))
|
||||||
|
vis = vis2;
|
||||||
|
else if (vis2 != (STV_DEFAULT << VT_VIS_SHIFT))
|
||||||
|
vis = (vis < vis2) ? vis : vis2;
|
||||||
|
sym->type.t = (sym->type.t & ~VT_VIS_MASK) | vis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* define a new external reference to a symbol 'v' */
|
/* define a new external reference to a symbol 'v' */
|
||||||
static Sym *external_sym(int v, CType *type, int r)
|
static Sym *external_sym(int v, CType *type, int r)
|
||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
|
||||||
s = sym_find(v);
|
s = sym_find(v);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
/* push forward reference */
|
/* push forward reference */
|
||||||
s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
|
s = sym_push(v, type, r | VT_CONST | VT_SYM, 0);
|
||||||
s->type.t |= VT_EXTERN;
|
s->type.t |= VT_EXTERN;
|
||||||
} else if (s->type.ref == func_old_type.ref) {
|
} else {
|
||||||
s->type.ref = type->ref;
|
if (s->type.ref == func_old_type.ref) {
|
||||||
s->r = r | VT_CONST | VT_SYM;
|
s->type.ref = type->ref;
|
||||||
s->type.t |= VT_EXTERN;
|
s->r = r | VT_CONST | VT_SYM;
|
||||||
} else if (!is_compatible_types(&s->type, type)) {
|
s->type.t |= VT_EXTERN;
|
||||||
tcc_error("incompatible types for redefinition of '%s'",
|
}
|
||||||
get_tok_str(v, NULL));
|
patch_storage(s, type);
|
||||||
|
update_storage(s);
|
||||||
}
|
}
|
||||||
/* Merge some storage attributes. */
|
|
||||||
if (type->t & VT_WEAK)
|
|
||||||
weaken_symbol(s);
|
|
||||||
|
|
||||||
if (type->t & VT_VIS_MASK)
|
|
||||||
apply_visibility(s, type);
|
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,7 +1159,6 @@ ST_FUNC int gv(int rc)
|
|||||||
rc2 = RC_QRET;
|
rc2 = RC_QRET;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* need to reload if:
|
/* need to reload if:
|
||||||
- constant
|
- constant
|
||||||
- lvalue (need to dereference pointer)
|
- lvalue (need to dereference pointer)
|
||||||
@ -3733,7 +3727,7 @@ static void parse_btype_qualify(CType *type, int qualifiers)
|
|||||||
*/
|
*/
|
||||||
static int parse_btype(CType *type, AttributeDef *ad)
|
static int parse_btype(CType *type, AttributeDef *ad)
|
||||||
{
|
{
|
||||||
int t, u, bt_size, complete, type_found, typespec_found;
|
int t, u, bt_size, complete, type_found, typespec_found, g;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
CType type1;
|
CType type1;
|
||||||
|
|
||||||
@ -3865,15 +3859,18 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
|||||||
|
|
||||||
/* storage */
|
/* storage */
|
||||||
case TOK_EXTERN:
|
case TOK_EXTERN:
|
||||||
t |= VT_EXTERN;
|
g = VT_EXTERN;
|
||||||
next();
|
goto storage;
|
||||||
break;
|
|
||||||
case TOK_STATIC:
|
case TOK_STATIC:
|
||||||
t |= VT_STATIC;
|
g = VT_STATIC;
|
||||||
next();
|
goto storage;
|
||||||
break;
|
|
||||||
case TOK_TYPEDEF:
|
case TOK_TYPEDEF:
|
||||||
t |= VT_TYPEDEF;
|
g = VT_TYPEDEF;
|
||||||
|
goto storage;
|
||||||
|
storage:
|
||||||
|
if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g)
|
||||||
|
tcc_error("multiple storage classes");
|
||||||
|
t |= g;
|
||||||
next();
|
next();
|
||||||
break;
|
break;
|
||||||
case TOK_INLINE1:
|
case TOK_INLINE1:
|
||||||
@ -4203,6 +4200,7 @@ static void type_decl(CType *type, AttributeDef *ad, int *v, int td)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*type = type1;
|
*type = type1;
|
||||||
|
type->t |= storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compute the lvalue VT_LVAL_xxx needed to match type t. */
|
/* compute the lvalue VT_LVAL_xxx needed to match type t. */
|
||||||
@ -5986,7 +5984,11 @@ static void parse_init_elem(int expr_type)
|
|||||||
expr_const1();
|
expr_const1();
|
||||||
global_expr = saved_global_expr;
|
global_expr = saved_global_expr;
|
||||||
/* NOTE: symbols are accepted */
|
/* NOTE: symbols are accepted */
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST)
|
if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST
|
||||||
|
#ifdef TCC_TARGET_PE
|
||||||
|
|| (vtop->type.t & VT_IMPORT)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
tcc_error("initializer element is not constant");
|
tcc_error("initializer element is not constant");
|
||||||
break;
|
break;
|
||||||
case EXPR_ANY:
|
case EXPR_ANY:
|
||||||
@ -6656,16 +6658,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
vset(type, r, addr);
|
vset(type, r, addr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Sym *sym;
|
Sym *sym = NULL;
|
||||||
|
|
||||||
sym = NULL;
|
|
||||||
if (v && scope == VT_CONST) {
|
if (v && scope == VT_CONST) {
|
||||||
/* see if the symbol was already defined */
|
/* see if the symbol was already defined */
|
||||||
sym = sym_find(v);
|
sym = sym_find(v);
|
||||||
if (sym) {
|
if (sym) {
|
||||||
if (!is_compatible_types(&sym->type, type))
|
patch_storage(sym, type);
|
||||||
tcc_error("incompatible types for redefinition of '%s'",
|
|
||||||
get_tok_str(v, NULL));
|
|
||||||
if (sym->type.t & VT_EXTERN) {
|
if (sym->type.t & VT_EXTERN) {
|
||||||
/* if the variable is extern, it was not allocated */
|
/* if the variable is extern, it was not allocated */
|
||||||
sym->type.t &= ~VT_EXTERN;
|
sym->type.t &= ~VT_EXTERN;
|
||||||
@ -6675,16 +6673,18 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
sym->type.ref->c < 0 &&
|
sym->type.ref->c < 0 &&
|
||||||
type->ref->c >= 0)
|
type->ref->c >= 0)
|
||||||
sym->type.ref->c = type->ref->c;
|
sym->type.ref->c = type->ref->c;
|
||||||
} else {
|
} else if (!has_init) {
|
||||||
/* we accept several definitions of the same
|
/* we accept several definitions of the same
|
||||||
global variable. this is tricky, because we
|
global variable. this is tricky, because we
|
||||||
must play with the SHN_COMMON type of the symbol */
|
must play with the SHN_COMMON type of the symbol */
|
||||||
/* XXX: should check if the variable was already
|
|
||||||
initialized. It is incorrect to initialized it
|
|
||||||
twice */
|
|
||||||
/* no init data, we won't add more to the symbol */
|
/* no init data, we won't add more to the symbol */
|
||||||
if (!has_init)
|
update_storage(sym);
|
||||||
goto no_alloc;
|
goto no_alloc;
|
||||||
|
} else if (sym->c) {
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
||||||
|
if (esym->st_shndx == data_section->sh_num)
|
||||||
|
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6697,6 +6697,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
else if (tcc_state->nocommon)
|
else if (tcc_state->nocommon)
|
||||||
sec = bss_section;
|
sec = bss_section;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sec) {
|
if (sec) {
|
||||||
data_offset = sec->data_offset;
|
data_offset = sec->data_offset;
|
||||||
data_offset = (data_offset + align - 1) & -align;
|
data_offset = (data_offset + align - 1) & -align;
|
||||||
@ -6730,22 +6731,15 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
if (sec) {
|
if (sec) {
|
||||||
put_extern_sym(sym, sec, addr, size);
|
put_extern_sym(sym, sec, addr, size);
|
||||||
} else {
|
} else {
|
||||||
ElfW(Sym) *esym;
|
put_extern_sym(sym, SECTION_COMMON, align, size);
|
||||||
/* put a common area */
|
|
||||||
put_extern_sym(sym, NULL, align, size);
|
|
||||||
/* XXX: find a nicer way */
|
|
||||||
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
|
||||||
esym->st_shndx = SHN_COMMON;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* push global reference */
|
/* push global reference */
|
||||||
sym = get_sym_ref(type, sec, addr, size);
|
sym = get_sym_ref(type, sec, addr, size);
|
||||||
vpushsym(type, sym);
|
vpushsym(type, sym);
|
||||||
}
|
}
|
||||||
/* patch symbol weakness */
|
|
||||||
if (type->t & VT_WEAK)
|
|
||||||
weaken_symbol(sym);
|
|
||||||
apply_visibility(sym, type);
|
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
/* handles bounds now because the symbol must be defined
|
/* handles bounds now because the symbol must be defined
|
||||||
before for the relocation */
|
before for the relocation */
|
||||||
@ -6760,6 +6754,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->t & VT_VLA) {
|
if (type->t & VT_VLA) {
|
||||||
int a;
|
int a;
|
||||||
|
|
||||||
@ -6775,6 +6770,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
gen_vla_sp_save(addr);
|
gen_vla_sp_save(addr);
|
||||||
vla_sp_loc = addr;
|
vla_sp_loc = addr;
|
||||||
vlas_in_scope++;
|
vlas_in_scope++;
|
||||||
|
|
||||||
} else if (has_init) {
|
} else if (has_init) {
|
||||||
size_t oldreloc_offset = 0;
|
size_t oldreloc_offset = 0;
|
||||||
if (sec && sec->reloc)
|
if (sec && sec->reloc)
|
||||||
@ -6787,7 +6783,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
if (flexible_array)
|
if (flexible_array)
|
||||||
flexible_array->type.ref->c = -1;
|
flexible_array->type.ref->c = -1;
|
||||||
}
|
}
|
||||||
no_alloc: ;
|
|
||||||
|
no_alloc:
|
||||||
/* restore parse state if needed */
|
/* restore parse state if needed */
|
||||||
if (init_str) {
|
if (init_str) {
|
||||||
end_macro();
|
end_macro();
|
||||||
@ -6878,10 +6875,6 @@ static void gen_function(Sym *sym)
|
|||||||
/* patch symbol size */
|
/* patch symbol size */
|
||||||
((ElfW(Sym) *)symtab_section->data)[sym->c].st_size =
|
((ElfW(Sym) *)symtab_section->data)[sym->c].st_size =
|
||||||
ind - func_ind;
|
ind - func_ind;
|
||||||
/* patch symbol weakness (this definition overrules any prototype) */
|
|
||||||
if (sym->type.t & VT_WEAK)
|
|
||||||
weaken_symbol(sym);
|
|
||||||
apply_visibility(sym, &sym->type);
|
|
||||||
tcc_debug_funcend(tcc_state, ind - func_ind);
|
tcc_debug_funcend(tcc_state, ind - func_ind);
|
||||||
/* It's better to crash than to generate wrong code */
|
/* It's better to crash than to generate wrong code */
|
||||||
cur_text_section = NULL;
|
cur_text_section = NULL;
|
||||||
@ -7022,10 +7015,14 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
if (ad.a.weak)
|
if (ad.a.weak)
|
||||||
type.t |= VT_WEAK;
|
type.t |= VT_WEAK;
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
if (ad.a.func_import)
|
if (ad.a.func_import || ad.a.func_export) {
|
||||||
type.t |= VT_IMPORT;
|
if (type.t & (VT_STATIC|VT_TYPEDEF))
|
||||||
if (ad.a.func_export)
|
tcc_error("cannot have dll linkage with static or typedef");
|
||||||
type.t |= VT_EXPORT;
|
if (ad.a.func_export)
|
||||||
|
type.t |= VT_EXPORT;
|
||||||
|
else if ((type.t & VT_BTYPE) != VT_FUNC)
|
||||||
|
type.t |= VT_IMPORT|VT_EXTERN;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
type.t |= ad.a.visibility << VT_VIS_SHIFT;
|
type.t |= ad.a.visibility << VT_VIS_SHIFT;
|
||||||
|
|
||||||
@ -7058,10 +7055,6 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
&& type.ref->a.func_call == FUNC_CDECL)
|
&& type.ref->a.func_call == FUNC_CDECL)
|
||||||
type.ref->a.func_call = ref->a.func_call;
|
type.ref->a.func_call = ref->a.func_call;
|
||||||
|
|
||||||
/* use export from prototype */
|
|
||||||
if (ref->a.func_export)
|
|
||||||
type.ref->a.func_export = 1;
|
|
||||||
|
|
||||||
/* use static from prototype */
|
/* use static from prototype */
|
||||||
if (sym->type.t & VT_STATIC)
|
if (sym->type.t & VT_STATIC)
|
||||||
type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
|
type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
|
||||||
@ -7071,6 +7064,9 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
if (! (type.t & VT_VIS_MASK))
|
if (! (type.t & VT_VIS_MASK))
|
||||||
type.t |= sym->type.t & VT_VIS_MASK;
|
type.t |= sym->type.t & VT_VIS_MASK;
|
||||||
|
|
||||||
|
/* apply other storage attributes from prototype */
|
||||||
|
type.t |= sym->type.t & (VT_EXPORT|VT_WEAK);
|
||||||
|
|
||||||
if (!is_compatible_types(&sym->type, &type)) {
|
if (!is_compatible_types(&sym->type, &type)) {
|
||||||
func_error1:
|
func_error1:
|
||||||
tcc_error("incompatible types for redefinition of '%s'",
|
tcc_error("incompatible types for redefinition of '%s'",
|
||||||
@ -7134,7 +7130,7 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (btype.t & VT_TYPEDEF) {
|
if (type.t & VT_TYPEDEF) {
|
||||||
/* save typedefed type */
|
/* save typedefed type */
|
||||||
/* XXX: test storage specifiers ? */
|
/* XXX: test storage specifiers ? */
|
||||||
sym = sym_find(v);
|
sym = sym_find(v);
|
||||||
@ -7148,7 +7144,6 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
sym = sym_push(v, &type, 0, 0);
|
sym = sym_push(v, &type, 0, 0);
|
||||||
}
|
}
|
||||||
sym->a = ad.a;
|
sym->a = ad.a;
|
||||||
sym->type.t |= VT_TYPEDEF;
|
|
||||||
} else {
|
} else {
|
||||||
r = 0;
|
r = 0;
|
||||||
if ((type.t & VT_BTYPE) == VT_FUNC) {
|
if ((type.t & VT_BTYPE) == VT_FUNC) {
|
||||||
@ -7162,7 +7157,7 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
has_init = (tok == '=');
|
has_init = (tok == '=');
|
||||||
if (has_init && (type.t & VT_VLA))
|
if (has_init && (type.t & VT_VLA))
|
||||||
tcc_error("variable length array cannot be initialized");
|
tcc_error("variable length array cannot be initialized");
|
||||||
if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) ||
|
if ((type.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) ||
|
||||||
((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
|
((type.t & VT_ARRAY) && (type.t & VT_STATIC) &&
|
||||||
!has_init && l == VT_CONST && type.ref->c < 0)) {
|
!has_init && l == VT_CONST && type.ref->c < 0)) {
|
||||||
/* external variable or function */
|
/* external variable or function */
|
||||||
@ -7171,7 +7166,6 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
extern */
|
extern */
|
||||||
sym = external_sym(v, &type, r);
|
sym = external_sym(v, &type, r);
|
||||||
sym->asm_label = ad.asm_label;
|
sym->asm_label = ad.asm_label;
|
||||||
|
|
||||||
if (ad.alias_target) {
|
if (ad.alias_target) {
|
||||||
Section tsec;
|
Section tsec;
|
||||||
ElfW(Sym) *esym;
|
ElfW(Sym) *esym;
|
||||||
@ -7185,7 +7179,6 @@ static int decl0(int l, int is_for_loop_init)
|
|||||||
put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0);
|
put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type.t |= (btype.t & VT_STATIC); /* Retain "static". */
|
|
||||||
if (type.t & VT_STATIC)
|
if (type.t & VT_STATIC)
|
||||||
r |= VT_CONST;
|
r |= VT_CONST;
|
||||||
else
|
else
|
||||||
|
41
tccpe.c
41
tccpe.c
@ -396,9 +396,11 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
|
|||||||
char buffer[200];
|
char buffer[200];
|
||||||
const char *s, *p;
|
const char *s, *p;
|
||||||
int sym_index = 0, n = 0;
|
int sym_index = 0, n = 0;
|
||||||
|
int a, err = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
s = pe_export_name(s1, sym);
|
s = pe_export_name(s1, sym);
|
||||||
|
a = 0;
|
||||||
if (n) {
|
if (n) {
|
||||||
/* second try: */
|
/* second try: */
|
||||||
if (sym->st_other & ST_PE_STDCALL) {
|
if (sym->st_other & ST_PE_STDCALL) {
|
||||||
@ -409,19 +411,24 @@ static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
|
|||||||
strcpy(buffer, s+1)[p-s-1] = 0;
|
strcpy(buffer, s+1)[p-s-1] = 0;
|
||||||
} else if (s[0] != '_') { /* try non-ansi function */
|
} else if (s[0] != '_') { /* try non-ansi function */
|
||||||
buffer[0] = '_', strcpy(buffer + 1, s);
|
buffer[0] = '_', strcpy(buffer + 1, s);
|
||||||
} else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */
|
} else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */
|
||||||
strcpy(buffer, s + 6);
|
strcpy(buffer, s + 6), a = 1;
|
||||||
} else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */
|
} else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */
|
||||||
strcpy(buffer, s + 6);
|
strcpy(buffer, s + 6), a = 1;
|
||||||
} else {
|
} else {
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
s = buffer;
|
s = buffer;
|
||||||
}
|
}
|
||||||
sym_index = find_elf_sym(s1->dynsymtab_section, s);
|
sym_index = find_elf_sym(s1->dynsymtab_section, s);
|
||||||
// printf("find (%d) %d %s\n", n, sym_index, s);
|
// printf("find (%d) %d %s\n", n, sym_index, s);
|
||||||
|
if (sym_index
|
||||||
|
&& ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT
|
||||||
|
&& 0 == (sym->st_other & ST_PE_IMPORT)
|
||||||
|
&& 0 == a
|
||||||
|
) err = -1, sym_index = 0;
|
||||||
} while (0 == sym_index && ++n < 2);
|
} while (0 == sym_index && ++n < 2);
|
||||||
return sym_index;
|
return n == 2 ? err : sym_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
@ -1239,7 +1246,7 @@ static int pe_check_symbols(struct pe_info *pe)
|
|||||||
int imp_sym = pe_find_import(pe->s1, sym);
|
int imp_sym = pe_find_import(pe->s1, sym);
|
||||||
struct import_symbol *is;
|
struct import_symbol *is;
|
||||||
|
|
||||||
if (0 == imp_sym)
|
if (imp_sym <= 0)
|
||||||
goto not_found;
|
goto not_found;
|
||||||
|
|
||||||
if (type == STT_NOTYPE) {
|
if (type == STT_NOTYPE) {
|
||||||
@ -1313,7 +1320,8 @@ static int pe_check_symbols(struct pe_info *pe)
|
|||||||
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
|
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
|
||||||
/* STB_WEAK undefined symbols are accepted */
|
/* STB_WEAK undefined symbols are accepted */
|
||||||
continue;
|
continue;
|
||||||
tcc_error_noabort("undefined symbol '%s'", name);
|
tcc_error_noabort("undefined symbol '%s'%s", name,
|
||||||
|
imp_sym < 0 ? ", missing __declspec(dllimport)?":"");
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
} else if (pe->s1->rdynamic
|
} else if (pe->s1->rdynamic
|
||||||
@ -1470,23 +1478,12 @@ static void pe_print_sections(TCCState *s1, const char *fname)
|
|||||||
#ifndef TCC_TARGET_ARM
|
#ifndef TCC_TARGET_ARM
|
||||||
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
||||||
{
|
{
|
||||||
Sym *sym;
|
|
||||||
ElfW(Sym) *esym;
|
|
||||||
int r2;
|
int r2;
|
||||||
|
|
||||||
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
|
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
|
||||||
return sv;
|
return sv;
|
||||||
sym = sv->sym;
|
if (!(sv->sym->type.t & VT_IMPORT))
|
||||||
if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN)
|
|
||||||
return sv;
|
return sv;
|
||||||
if (!sym->c)
|
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
|
||||||
put_extern_sym(sym, NULL, 0, 0);
|
|
||||||
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
|
|
||||||
if (!(esym->st_other & ST_PE_IMPORT))
|
|
||||||
return sv;
|
|
||||||
|
|
||||||
// printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
|
|
||||||
|
|
||||||
memset(v2, 0, sizeof *v2);
|
memset(v2, 0, sizeof *v2);
|
||||||
v2->type.t = VT_PTR;
|
v2->type.t = VT_PTR;
|
||||||
v2->r = VT_CONST | VT_SYM | VT_LVAL;
|
v2->r = VT_CONST | VT_SYM | VT_LVAL;
|
||||||
@ -1495,14 +1492,12 @@ ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
|
|||||||
r2 = get_reg(RC_INT);
|
r2 = get_reg(RC_INT);
|
||||||
load(r2, v2);
|
load(r2, v2);
|
||||||
v2->r = r2;
|
v2->r = r2;
|
||||||
|
|
||||||
if ((uint32_t)sv->c.i) {
|
if ((uint32_t)sv->c.i) {
|
||||||
vpushv(v2);
|
vpushv(v2);
|
||||||
vpushi(sv->c.i);
|
vpushi(sv->c.i);
|
||||||
gen_opi('+');
|
gen_opi('+');
|
||||||
*v2 = *vtop--;
|
*v2 = *vtop--;
|
||||||
}
|
}
|
||||||
|
|
||||||
v2->type.t = sv->type.t;
|
v2->type.t = sv->type.t;
|
||||||
v2->r |= sv->r & VT_LVAL;
|
v2->r |= sv->r & VT_LVAL;
|
||||||
return v2;
|
return v2;
|
||||||
|
@ -4,9 +4,10 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#define DLL_EXPORT __declspec(dllexport)
|
|
||||||
|
|
||||||
DLL_EXPORT void HelloWorld (void)
|
__declspec(dllexport) const char *hello_data = "(not set)";
|
||||||
|
|
||||||
|
__declspec(dllexport) void hello_func (void)
|
||||||
{
|
{
|
||||||
MessageBox (0, "Hello World!", "From DLL", MB_ICONINFORMATION);
|
MessageBox (0, hello_data, "From DLL", MB_ICONINFORMATION);
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,16 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
void HelloWorld (void);
|
void hello_func (void);
|
||||||
|
__declspec(dllimport) extern const char *hello_data;
|
||||||
|
|
||||||
int WINAPI WinMain(
|
int WINAPI WinMain(
|
||||||
HINSTANCE hInstance,
|
HINSTANCE hInstance,
|
||||||
HINSTANCE hPrevInstance,
|
HINSTANCE hPrevInstance,
|
||||||
LPSTR lpCmdLine,
|
LPSTR lpCmdLine,
|
||||||
int nCmdShow)
|
int nCmdShow)
|
||||||
{
|
{
|
||||||
HelloWorld();
|
hello_data = "Hello World!";
|
||||||
return 0;
|
hello_func();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user