Subversion Repositories Kolibri OS

Rev

Rev 6574 | Rev 8154 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6429 siemargl 1
/*
2
 *  TCC - Tiny C Compiler
3
 *
4
 *  Copyright (c) 2001-2004 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
 
21
#include "tcc.h"
22
 
23
/********************************************************/
24
/* global variables */
25
 
26
/* use GNU C extensions */
27
ST_DATA int gnu_ext = 1;
28
 
29
/* use TinyCC extensions */
30
ST_DATA int tcc_ext = 1;
31
 
32
/* XXX: get rid of this ASAP */
33
ST_DATA struct TCCState *tcc_state;
34
 
35
/********************************************************/
36
 
37
#ifdef ONE_SOURCE
38
#include "tccpp.c"
39
#include "tccgen.c"
40
#include "tccelf.c"
41
#ifdef TCC_IS_NATIVE
42
# include "tccrun.c"
43
#endif
44
#ifdef TCC_TARGET_I386
45
#include "i386-gen.c"
46
#endif
47
#ifdef TCC_TARGET_ARM
48
#include "arm-gen.c"
49
#endif
50
#ifdef TCC_TARGET_ARM64
51
#include "arm64-gen.c"
52
#endif
53
#ifdef TCC_TARGET_C67
54
#include "c67-gen.c"
55
#endif
56
#ifdef TCC_TARGET_X86_64
57
#include "x86_64-gen.c"
58
#endif
59
#ifdef CONFIG_TCC_ASM
60
#include "tccasm.c"
61
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
62
#include "i386-asm.c"
63
#endif
64
#endif
65
#ifdef TCC_TARGET_COFF
66
#include "tcccoff.c"
67
#endif
68
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS)
69
#include "tccpe.c"
70
#endif
71
#ifdef TCC_TARGET_MEOS
72
#include "tccmeos.c"
73
#endif
74
 
75
#endif /* ONE_SOURCE */
76
 
77
/********************************************************/
78
#ifndef CONFIG_TCC_ASM
79
ST_FUNC void asm_instr(void)
80
{
81
    tcc_error("inline asm() not supported");
82
}
83
ST_FUNC void asm_global_instr(void)
84
{
85
    tcc_error("inline asm() not supported");
86
}
87
#endif
88
 
7520 siemargl 89
 
90
 
6429 siemargl 91
/********************************************************/
92
#ifdef _WIN32
93
static char *normalize_slashes(char *path)
94
{
95
    char *p;
96
    for (p = path; *p; ++p)
97
        if (*p == '\\')
98
            *p = '/';
99
    return path;
100
}
101
 
102
static HMODULE tcc_module;
103
 
104
/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */
105
static void tcc_set_lib_path_w32(TCCState *s)
106
{
107
    char path[1024], *p;
108
    GetModuleFileNameA(tcc_module, path, sizeof path);
109
    p = tcc_basename(normalize_slashes(strlwr(path)));
110
    if (p - 5 > path && 0 == strncmp(p - 5, "/bin/", 5))
111
        p -= 5;
112
    else if (p > path)
113
        p--;
114
    *p = 0;
115
    tcc_set_lib_path(s, path);
116
}
117
 
118
#ifdef TCC_TARGET_PE
119
static void tcc_add_systemdir(TCCState *s)
120
{
121
    char buf[1000];
122
    GetSystemDirectory(buf, sizeof buf);
123
    tcc_add_library_path(s, normalize_slashes(buf));
124
}
125
#endif
126
 
127
#ifndef CONFIG_TCC_STATIC
128
void dlclose(void *p)
129
{
130
    FreeLibrary((HMODULE)p);
131
}
132
#endif
133
 
134
#ifdef LIBTCC_AS_DLL
135
BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
136
{
137
    if (DLL_PROCESS_ATTACH == dwReason)
138
        tcc_module = hDll;
139
    return TRUE;
140
}
141
#endif
7520 siemargl 142
#else // _WIN32
143
#ifdef TCC_TARGET_MEOS
144
/* on Kolibri host, we suppose the lib and includes are at the location of 'tcc' /lib, /include */
145
static void tcc_set_lib_path_kos(TCCState *s)
146
{
147
	char** argv0 = (char**)0x20; // path in kolibri header
148
    char path[1024], *p;
149
	strncpy(path, *argv0, sizeof path);
150
	p = tcc_basename(path);
151
    if (p > path) p--;
152
    *p = 0;
153
    tcc_set_lib_path(s, path);
154
}
6429 siemargl 155
#endif
7520 siemargl 156
#endif
6429 siemargl 157
 
158
/********************************************************/
159
/* copy a string and truncate it. */
160
PUB_FUNC char *pstrcpy(char *buf, int buf_size, const char *s)
161
{
162
    char *q, *q_end;
163
    int c;
164
 
165
    if (buf_size > 0) {
166
        q = buf;
167
        q_end = buf + buf_size - 1;
168
        while (q < q_end) {
169
            c = *s++;
170
            if (c == '\0')
171
                break;
172
            *q++ = c;
173
        }
174
        *q = '\0';
175
    }
176
    return buf;
177
}
178
 
179
/* strcat and truncate. */
180
PUB_FUNC char *pstrcat(char *buf, int buf_size, const char *s)
181
{
182
    int len;
183
    len = strlen(buf);
184
    if (len < buf_size)
185
        pstrcpy(buf + len, buf_size - len, s);
186
    return buf;
187
}
188
 
189
PUB_FUNC char *pstrncpy(char *out, const char *in, size_t num)
190
{
191
    memcpy(out, in, num);
192
    out[num] = '\0';
193
    return out;
194
}
195
 
196
/* extract the basename of a file */
197
PUB_FUNC char *tcc_basename(const char *name)
198
{
199
    char *p = strchr(name, 0);
200
    while (p > name && !IS_DIRSEP(p[-1]))
201
        --p;
202
    return p;
203
}
204
 
205
/* extract extension part of a file
206
 *
207
 * (if no extension, return pointer to end-of-string)
208
 */
209
PUB_FUNC char *tcc_fileextension (const char *name)
210
{
211
    char *b = tcc_basename(name);
212
    char *e = strrchr(b, '.');
213
    return e ? e : strchr(b, 0);
214
}
215
 
216
/********************************************************/
217
/* memory management */
218
 
219
#undef free
220
#undef malloc
221
#undef realloc
222
 
223
#ifndef MEM_DEBUG
224
 
225
PUB_FUNC void tcc_free(void *ptr)
226
{
227
    free(ptr);
228
}
229
 
230
PUB_FUNC void *tcc_malloc(unsigned long size)
231
{
232
    void *ptr;
233
    ptr = malloc(size);
234
    if (!ptr && size)
235
        tcc_error("memory full (malloc)");
236
    return ptr;
237
}
238
 
239
PUB_FUNC void *tcc_mallocz(unsigned long size)
240
{
241
    void *ptr;
242
    ptr = tcc_malloc(size);
243
    memset(ptr, 0, size);
244
    return ptr;
245
}
246
 
247
PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size)
248
{
249
    void *ptr1;
250
    ptr1 = realloc(ptr, size);
251
    if (!ptr1 && size)
252
        tcc_error("memory full (realloc)");
253
    return ptr1;
254
}
255
 
256
PUB_FUNC char *tcc_strdup(const char *str)
257
{
258
    char *ptr;
259
    ptr = tcc_malloc(strlen(str) + 1);
260
    strcpy(ptr, str);
261
    return ptr;
262
}
263
 
264
PUB_FUNC void tcc_memstats(int bench)
265
{
266
}
267
 
268
#else
269
 
270
#define MEM_DEBUG_MAGIC1 0xFEEDDEB1
271
#define MEM_DEBUG_MAGIC2 0xFEEDDEB2
272
#define MEM_DEBUG_FILE_LEN 15
273
 
274
struct mem_debug_header {
275
    size_t      magic1;
276
    size_t      size;
277
    struct mem_debug_header *prev;
278
    struct mem_debug_header *next;
279
    size_t      line_num;
280
    char        file_name[MEM_DEBUG_FILE_LEN + 1];
281
    size_t      magic2;
282
};
283
 
284
typedef struct mem_debug_header mem_debug_header_t;
285
 
286
static mem_debug_header_t *mem_debug_chain;
287
static size_t mem_cur_size;
288
static size_t mem_max_size;
289
 
290
PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
291
{
292
    void *ptr;
293
    int ofs;
294
 
295
    mem_debug_header_t *header;
296
 
297
    ptr = malloc(sizeof(mem_debug_header_t) + size);
298
    if (!ptr)
299
        tcc_error("memory full (malloc)");
300
 
301
    mem_cur_size += size;
302
    if (mem_cur_size > mem_max_size)
303
        mem_max_size = mem_cur_size;
304
 
305
    header = (mem_debug_header_t *)ptr;
306
 
307
    header->magic1 = MEM_DEBUG_MAGIC1;
308
    header->magic2 = MEM_DEBUG_MAGIC2;
309
    header->size = size;
310
    header->line_num = line;
311
 
312
    ofs = strlen(file) - MEM_DEBUG_FILE_LEN;
313
    strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
314
    header->file_name[MEM_DEBUG_FILE_LEN] = 0;
315
 
316
    header->next = mem_debug_chain;
317
    header->prev = NULL;
318
 
319
    if (header->next)
320
        header->next->prev = header;
321
 
322
    mem_debug_chain = header;
323
 
324
    ptr = (char *)ptr + sizeof(mem_debug_header_t);
325
    return ptr;
326
}
327
 
328
PUB_FUNC void tcc_free_debug(void *ptr)
329
{
330
    mem_debug_header_t *header;
331
 
332
    if (!ptr)
333
        return;
334
 
335
    ptr = (char *)ptr - sizeof(mem_debug_header_t);
336
    header = (mem_debug_header_t *)ptr;
337
    if (header->magic1 != MEM_DEBUG_MAGIC1 ||
338
        header->magic2 != MEM_DEBUG_MAGIC2 ||
339
        header->size == (size_t)-1 )
340
    {
341
        tcc_error("tcc_free check failed");
342
    }
343
 
344
    mem_cur_size -= header->size;
345
    header->size = (size_t)-1;
6441 siemargl 346
 
6429 siemargl 347
    if (header->next)
348
        header->next->prev = header->prev;
349
 
350
    if (header->prev)
351
        header->prev->next = header->next;
352
 
353
    if (header == mem_debug_chain)
354
        mem_debug_chain = header->next;
355
 
356
    free(ptr);
357
}
358
 
359
 
360
PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line)
361
{
362
    void *ptr;
363
    ptr = tcc_malloc_debug(size,file,line);
364
    memset(ptr, 0, size);
365
    return ptr;
366
}
367
 
368
PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line)
369
{
370
    mem_debug_header_t *header;
371
    int mem_debug_chain_update = 0;
372
 
373
    if (!ptr) {
374
        ptr = tcc_malloc_debug(size, file, line);
375
        return ptr;
376
    }
377
 
378
    ptr = (char *)ptr - sizeof(mem_debug_header_t);
379
    header = (mem_debug_header_t *)ptr;
380
    if (header->magic1 != MEM_DEBUG_MAGIC1 ||
381
        header->magic2 != MEM_DEBUG_MAGIC2 ||
382
        header->size == (size_t)-1 )
383
    {
384
        check_error:
385
            tcc_error("tcc_realloc check failed");
386
    }
387
 
388
    mem_debug_chain_update = (header == mem_debug_chain);
389
 
390
    mem_cur_size -= header->size;
391
    ptr = realloc(ptr, sizeof(mem_debug_header_t) + size);
392
    if (!ptr)
393
        tcc_error("memory full (realloc)");
394
 
395
    header = (mem_debug_header_t *)ptr;
396
    if (header->magic1 != MEM_DEBUG_MAGIC1 ||
397
        header->magic2 != MEM_DEBUG_MAGIC2)
398
    {
399
        goto check_error;
400
    }
401
 
402
    mem_cur_size += size;
403
    if (mem_cur_size > mem_max_size)
404
        mem_max_size = mem_cur_size;
405
 
406
    header->size = size;
407
    if (header->next)
408
        header->next->prev = header;
409
 
410
    if (header->prev)
411
        header->prev->next = header;
412
 
413
    if (mem_debug_chain_update)
414
        mem_debug_chain = header;
415
 
416
    ptr = (char *)ptr + sizeof(mem_debug_header_t);
417
    return ptr;
418
}
419
 
420
PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line)
421
{
422
    char *ptr;
423
    ptr = tcc_malloc_debug(strlen(str) + 1, file, line);
424
    strcpy(ptr, str);
425
    return ptr;
426
}
427
 
428
PUB_FUNC void tcc_memstats(int bench)
429
{
430
    if (mem_cur_size) {
431
        mem_debug_header_t *header = mem_debug_chain;
432
 
433
        fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n",
434
            mem_cur_size, mem_max_size);
435
 
436
        while (header) {
437
            fprintf(stderr, "  file %s, line %u: %u bytes\n",
438
                header->file_name, header->line_num, header->size);
439
            header = header->next;
440
        }
441
    }
442
    else if (bench)
443
        fprintf(stderr, "mem_max_size= %d bytes\n", mem_max_size);
444
}
445
 
446
#undef MEM_DEBUG_MAGIC1
447
#undef MEM_DEBUG_MAGIC2
448
#undef MEM_DEBUG_FILE_LEN
449
 
450
#endif
451
 
452
#define free(p) use_tcc_free(p)
453
#define malloc(s) use_tcc_malloc(s)
454
#define realloc(p, s) use_tcc_realloc(p, s)
455
 
456
/********************************************************/
457
/* dynarrays */
458
 
459
ST_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
460
{
461
    int nb, nb_alloc;
462
    void **pp;
463
 
464
    nb = *nb_ptr;
465
    pp = *ptab;
466
    /* every power of two we double array size */
467
    if ((nb & (nb - 1)) == 0) {
468
        if (!nb)
469
            nb_alloc = 1;
470
        else
471
            nb_alloc = nb * 2;
472
        pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
473
        *ptab = pp;
474
    }
475
    pp[nb++] = data;
476
    *nb_ptr = nb;
477
}
478
 
479
ST_FUNC void dynarray_reset(void *pp, int *n)
480
{
481
    void **p;
482
    for (p = *(void***)pp; *n; ++p, --*n)
483
        if (*p)
484
            tcc_free(*p);
485
    tcc_free(*(void**)pp);
486
    *(void**)pp = NULL;
487
}
488
 
489
static void tcc_split_path(TCCState *s, void ***p_ary, int *p_nb_ary, const char *in)
490
{
491
    const char *p;
492
    do {
493
        int c;
494
        CString str;
495
 
496
        cstr_new(&str);
497
        for (p = in; c = *p, c != '\0' && c != PATHSEP; ++p) {
498
            if (c == '{' && p[1] && p[2] == '}') {
499
                c = p[1], p += 2;
500
                if (c == 'B')
501
                    cstr_cat(&str, s->tcc_lib_path, -1);
502
            } else {
503
                cstr_ccat(&str, c);
504
            }
505
        }
506
        cstr_ccat(&str, '\0');
507
        dynarray_add(p_ary, p_nb_ary, tcc_strdup(str.data));
508
        cstr_free(&str);
509
        in = p+1;
510
    } while (*p);
511
}
512
 
513
/********************************************************/
514
 
515
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
516
{
517
    Section *sec;
518
 
519
    sec = tcc_mallocz(sizeof(Section) + strlen(name));
520
    strcpy(sec->name, name);
521
    sec->sh_type = sh_type;
522
    sec->sh_flags = sh_flags;
523
    switch(sh_type) {
524
    case SHT_HASH:
525
    case SHT_REL:
526
    case SHT_RELA:
527
    case SHT_DYNSYM:
528
    case SHT_SYMTAB:
529
    case SHT_DYNAMIC:
530
        sec->sh_addralign = 4;
531
        break;
532
    case SHT_STRTAB:
533
        sec->sh_addralign = 1;
534
        break;
535
    default:
536
        sec->sh_addralign =  PTR_SIZE; /* gcc/pcc default aligment */
537
        break;
538
    }
539
 
540
    if (sh_flags & SHF_PRIVATE) {
541
        dynarray_add((void ***)&s1->priv_sections, &s1->nb_priv_sections, sec);
542
    } else {
543
        sec->sh_num = s1->nb_sections;
544
        dynarray_add((void ***)&s1->sections, &s1->nb_sections, sec);
545
    }
546
 
547
    return sec;
548
}
549
 
550
static void free_section(Section *s)
551
{
552
    tcc_free(s->data);
553
}
554
 
555
/* realloc section and set its content to zero */
556
ST_FUNC void section_realloc(Section *sec, unsigned long new_size)
557
{
558
    unsigned long size;
559
    unsigned char *data;
560
 
561
    size = sec->data_allocated;
562
    if (size == 0)
563
        size = 1;
564
    while (size < new_size)
565
        size = size * 2;
566
    data = tcc_realloc(sec->data, size);
567
    memset(data + sec->data_allocated, 0, size - sec->data_allocated);
568
    sec->data = data;
569
    sec->data_allocated = size;
570
}
571
 
572
/* reserve at least 'size' bytes in section 'sec' from
573
   sec->data_offset. */
574
ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
575
{
576
    size_t offset, offset1;
577
 
578
    offset = sec->data_offset;
579
    offset1 = offset + size;
580
    if (offset1 > sec->data_allocated)
581
        section_realloc(sec, offset1);
582
    sec->data_offset = offset1;
583
    return sec->data + offset;
584
}
585
 
586
/* reserve at least 'size' bytes from section start */
587
ST_FUNC void section_reserve(Section *sec, unsigned long size)
588
{
589
    if (size > sec->data_allocated)
590
        section_realloc(sec, size);
591
    if (size > sec->data_offset)
592
        sec->data_offset = size;
593
}
594
 
595
/* return a reference to a section, and create it if it does not
596
   exists */
597
ST_FUNC Section *find_section(TCCState *s1, const char *name)
598
{
599
    Section *sec;
600
    int i;
601
    for(i = 1; i < s1->nb_sections; i++) {
602
        sec = s1->sections[i];
603
        if (!strcmp(name, sec->name))
604
            return sec;
605
    }
606
    /* sections are created as PROGBITS */
607
    return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
608
}
609
 
610
/* update sym->c so that it points to an external symbol in section
611
   'section' with value 'value' */
612
ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
613
                            addr_t value, unsigned long size,
614
                            int can_add_underscore)
615
{
616
    int sym_type, sym_bind, sh_num, info, other;
617
    ElfW(Sym) *esym;
618
    const char *name;
619
    char buf1[256];
620
 
621
#ifdef CONFIG_TCC_BCHECK
622
    char buf[32];
623
#endif
624
 
625
    if (section == NULL)
626
        sh_num = SHN_UNDEF;
627
    else if (section == SECTION_ABS)
628
        sh_num = SHN_ABS;
629
    else
630
        sh_num = section->sh_num;
631
 
632
    if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
633
        sym_type = STT_FUNC;
634
    } else if ((sym->type.t & VT_BTYPE) == VT_VOID) {
635
        sym_type = STT_NOTYPE;
636
    } else {
637
        sym_type = STT_OBJECT;
638
    }
639
 
640
    if (sym->type.t & VT_STATIC)
641
        sym_bind = STB_LOCAL;
642
    else {
643
        if (sym->type.t & VT_WEAK)
644
            sym_bind = STB_WEAK;
645
        else
646
            sym_bind = STB_GLOBAL;
647
    }
648
 
649
    if (!sym->c) {
650
        name = get_tok_str(sym->v, NULL);
651
#ifdef CONFIG_TCC_BCHECK
652
        if (tcc_state->do_bounds_check) {
653
            /* XXX: avoid doing that for statics ? */
654
            /* if bound checking is activated, we change some function
655
               names by adding the "__bound" prefix */
656
            switch(sym->v) {
657
#ifdef TCC_TARGET_PE
658
            /* XXX: we rely only on malloc hooks */
659
            case TOK_malloc:
660
            case TOK_free:
661
            case TOK_realloc:
662
            case TOK_memalign:
663
            case TOK_calloc:
664
#endif
665
            case TOK_memcpy:
666
            case TOK_memmove:
667
            case TOK_memset:
668
            case TOK_strlen:
669
            case TOK_strcpy:
670
            case TOK_alloca:
671
                strcpy(buf, "__bound_");
672
                strcat(buf, name);
673
                name = buf;
674
                break;
675
            }
676
        }
677
#endif
678
        other = 0;
679
 
680
#ifdef TCC_TARGET_PE
681
        if (sym->type.t & VT_EXPORT)
682
            other |= ST_PE_EXPORT;
683
        if (sym_type == STT_FUNC && sym->type.ref) {
684
            Sym *ref = sym->type.ref;
685
            if (ref->a.func_export)
686
                other |= ST_PE_EXPORT;
687
            if (ref->a.func_call == FUNC_STDCALL && can_add_underscore) {
688
                sprintf(buf1, "_%s@%d", name, ref->a.func_args * PTR_SIZE);
689
                name = buf1;
690
                other |= ST_PE_STDCALL;
691
                can_add_underscore = 0;
692
            }
693
        } else {
694
            if (find_elf_sym(tcc_state->dynsymtab_section, name))
695
                other |= ST_PE_IMPORT;
696
            if (sym->type.t & VT_IMPORT)
697
                other |= ST_PE_IMPORT;
698
        }
699
#else
700
        if (! (sym->type.t & VT_STATIC))
701
	    other = (sym->type.t & VT_VIS_MASK) >> VT_VIS_SHIFT;
702
#endif
703
        if (tcc_state->leading_underscore && can_add_underscore) {
704
            buf1[0] = '_';
705
            pstrcpy(buf1 + 1, sizeof(buf1) - 1, name);
706
            name = buf1;
707
        }
708
        if (sym->asm_label) {
709
            name = get_tok_str(sym->asm_label, NULL);
710
        }
711
        info = ELFW(ST_INFO)(sym_bind, sym_type);
712
        sym->c = add_elf_sym(symtab_section, value, size, info, other, sh_num, name);
713
    } else {
714
        esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
715
        esym->st_value = value;
716
        esym->st_size = size;
717
        esym->st_shndx = sh_num;
718
    }
719
}
720
 
721
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
722
                           addr_t value, unsigned long size)
723
{
724
    put_extern_sym2(sym, section, value, size, 1);
725
}
726
 
727
/* add a new relocation entry to symbol 'sym' in section 's' */
728
ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type,
729
                     addr_t addend)
730
{
731
    int c = 0;
732
    if (sym) {
733
        if (0 == sym->c)
734
            put_extern_sym(sym, NULL, 0, 0);
735
        c = sym->c;
736
    }
737
    /* now we can add ELF relocation info */
738
    put_elf_reloca(symtab_section, s, offset, type, c, addend);
739
}
740
 
741
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
742
{
743
    greloca(s, sym, offset, type, 0);
744
}
745
 
746
/********************************************************/
747
 
748
static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
749
{
750
    int len;
751
    len = strlen(buf);
752
    vsnprintf(buf + len, buf_size - len, fmt, ap);
753
}
754
 
755
static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
756
{
757
    va_list ap;
758
    va_start(ap, fmt);
759
    strcat_vprintf(buf, buf_size, fmt, ap);
760
    va_end(ap);
761
}
762
 
763
static void error1(TCCState *s1, int is_warning, const char *fmt, va_list ap)
764
{
765
    char buf[2048];
766
    BufferedFile **pf, *f;
767
 
768
    buf[0] = '\0';
769
    /* use upper file if inline ":asm:" or token ":paste:" */
770
    for (f = file; f && f->filename[0] == ':'; f = f->prev)
771
     ;
772
    if (f) {
773
        for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++)
774
            strcat_printf(buf, sizeof(buf), "In file included from %s:%d:\n",
775
                (*pf)->filename, (*pf)->line_num);
776
        if (f->line_num > 0) {
777
            strcat_printf(buf, sizeof(buf), "%s:%d: ",
778
                f->filename, f->line_num);
779
        } else {
780
            strcat_printf(buf, sizeof(buf), "%s: ",
781
                f->filename);
782
        }
783
    } else {
784
        strcat_printf(buf, sizeof(buf), "tcc: ");
785
    }
786
    if (is_warning)
787
        strcat_printf(buf, sizeof(buf), "warning: ");
788
    else
789
        strcat_printf(buf, sizeof(buf), "error: ");
790
    strcat_vprintf(buf, sizeof(buf), fmt, ap);
791
 
792
    if (!s1->error_func) {
793
        /* default case: stderr */
794
        if (s1->ppfp) /* print a newline during tcc -E */
795
            fprintf(s1->ppfp, "\n"), fflush(s1->ppfp);
6574 siemargl 796
#ifndef TCC_TARGET_MEOS
6429 siemargl 797
        fprintf(stderr, "%s\n", buf);
798
        fflush(stderr); /* print error/warning now (win32) */
6574 siemargl 799
#else
800
        fprintf(stdout, "%s\n", buf);
801
        fflush(stdout); /* print error/warning now (win32) */
802
#endif
6429 siemargl 803
    } else {
804
        s1->error_func(s1->error_opaque, buf);
805
    }
806
    if (!is_warning || s1->warn_error)
807
        s1->nb_errors++;
808
}
809
 
810
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
811
                        void (*error_func)(void *opaque, const char *msg))
812
{
813
    s->error_opaque = error_opaque;
814
    s->error_func = error_func;
815
}
816
 
817
/* error without aborting current compilation */
818
PUB_FUNC void tcc_error_noabort(const char *fmt, ...)
819
{
820
    TCCState *s1 = tcc_state;
821
    va_list ap;
822
 
823
    va_start(ap, fmt);
824
    error1(s1, 0, fmt, ap);
825
    va_end(ap);
826
}
827
 
828
PUB_FUNC void tcc_error(const char *fmt, ...)
829
{
830
    TCCState *s1 = tcc_state;
831
    va_list ap;
832
 
833
    va_start(ap, fmt);
834
    error1(s1, 0, fmt, ap);
835
    va_end(ap);
836
    /* better than nothing: in some cases, we accept to handle errors */
837
    if (s1->error_set_jmp_enabled) {
838
        longjmp(s1->error_jmp_buf, 1);
839
    } else {
840
        /* XXX: eliminate this someday */
841
        exit(1);
842
    }
843
}
844
 
845
PUB_FUNC void tcc_warning(const char *fmt, ...)
846
{
847
    TCCState *s1 = tcc_state;
848
    va_list ap;
849
 
850
    if (s1->warn_none)
851
        return;
852
 
853
    va_start(ap, fmt);
854
    error1(s1, 1, fmt, ap);
855
    va_end(ap);
856
}
857
 
858
/********************************************************/
859
/* I/O layer */
860
 
861
ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen)
862
{
863
    BufferedFile *bf;
864
    int buflen = initlen ? initlen : IO_BUF_SIZE;
865
 
866
    bf = tcc_mallocz(sizeof(BufferedFile) + buflen);
867
    bf->buf_ptr = bf->buffer;
868
    bf->buf_end = bf->buffer + initlen;
869
    bf->buf_end[0] = CH_EOB; /* put eob symbol */
870
    pstrcpy(bf->filename, sizeof(bf->filename), filename);
871
#ifdef _WIN32
872
    normalize_slashes(bf->filename);
873
#endif
874
    bf->line_num = 1;
875
    bf->ifdef_stack_ptr = s1->ifdef_stack_ptr;
876
    bf->fd = -1;
877
    bf->prev = file;
878
    file = bf;
879
}
880
 
881
ST_FUNC void tcc_close(void)
882
{
883
    BufferedFile *bf = file;
884
    if (bf->fd > 0) {
885
        close(bf->fd);
886
        total_lines += bf->line_num;
887
    }
888
    file = bf->prev;
889
    tcc_free(bf);
890
}
891
 
892
ST_FUNC int tcc_open(TCCState *s1, const char *filename)
893
{
894
    int fd;
895
    if (strcmp(filename, "-") == 0)
896
        fd = 0, filename = "";
897
    else
898
        fd = open(filename, O_RDONLY | O_BINARY);
899
    if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3)
900
        printf("%s %*s%s\n", fd < 0 ? "nf":"->",
901
               (int)(s1->include_stack_ptr - s1->include_stack), "", filename);
902
    if (fd < 0)
903
        return -1;
904
 
905
    tcc_open_bf(s1, filename, 0);
906
    file->fd = fd;
907
    return fd;
908
}
909
 
910
/* compile the C file opened in 'file'. Return non zero if errors. */
911
static int tcc_compile(TCCState *s1)
912
{
913
    Sym *define_start;
914
    char buf[512];
915
    volatile int section_sym;
916
 
917
#ifdef INC_DEBUG
918
    printf("%s: **** new file\n", file->filename);
919
#endif
920
    preprocess_init(s1);
921
 
922
    cur_text_section = NULL;
923
    funcname = "";
924
    anon_sym = SYM_FIRST_ANOM;
925
 
926
    /* file info: full path + filename */
927
    section_sym = 0; /* avoid warning */
928
    if (s1->do_debug) {
929
        section_sym = put_elf_sym(symtab_section, 0, 0,
930
                                  ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
931
                                  text_section->sh_num, NULL);
932
        getcwd(buf, sizeof(buf));
933
#ifdef _WIN32
934
        normalize_slashes(buf);
935
#endif
936
        pstrcat(buf, sizeof(buf), "/");
937
        put_stabs_r(buf, N_SO, 0, 0,
938
                    text_section->data_offset, text_section, section_sym);
939
        put_stabs_r(file->filename, N_SO, 0, 0,
940
                    text_section->data_offset, text_section, section_sym);
941
    }
942
    /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
943
       symbols can be safely used */
944
    put_elf_sym(symtab_section, 0, 0,
945
                ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
946
                SHN_ABS, file->filename);
947
 
948
    /* define some often used types */
949
    int_type.t = VT_INT;
950
 
951
    char_pointer_type.t = VT_BYTE;
952
    mk_pointer(&char_pointer_type);
953
 
954
#if PTR_SIZE == 4
955
    size_type.t = VT_INT;
956
#else
957
    size_type.t = VT_LLONG;
958
#endif
959
 
960
    func_old_type.t = VT_FUNC;
961
    func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
962
#ifdef TCC_TARGET_ARM
963
    arm_init(s1);
964
#endif
965
 
966
#if 0
967
    /* define 'void *alloca(unsigned int)' builtin function */
968
    {
969
        Sym *s1;
970
 
971
        p = anon_sym++;
972
        sym = sym_push(p, mk_pointer(VT_VOID), FUNC_CDECL, FUNC_NEW);
973
        s1 = sym_push(SYM_FIELD, VT_UNSIGNED | VT_INT, 0, 0);
974
        s1->next = NULL;
975
        sym->next = s1;
976
        sym_push(TOK_alloca, VT_FUNC | (p << VT_STRUCT_SHIFT), VT_CONST, 0);
977
    }
978
#endif
979
 
980
    define_start = define_stack;
981
    nocode_wanted = 1;
982
 
983
    if (setjmp(s1->error_jmp_buf) == 0) {
984
        s1->nb_errors = 0;
985
        s1->error_set_jmp_enabled = 1;
986
 
987
        ch = file->buf_ptr[0];
988
        tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
989
        parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
990
        next();
991
        decl(VT_CONST);
992
        if (tok != TOK_EOF)
993
            expect("declaration");
994
        check_vstack();
995
 
996
        /* end of translation unit info */
997
        if (s1->do_debug) {
998
            put_stabs_r(NULL, N_SO, 0, 0,
999
                        text_section->data_offset, text_section, section_sym);
1000
        }
1001
    }
1002
 
1003
    s1->error_set_jmp_enabled = 0;
1004
 
1005
    /* reset define stack, but leave -Dsymbols (may be incorrect if
1006
       they are undefined) */
1007
    free_defines(define_start);
1008
 
1009
    gen_inline_functions();
1010
 
1011
    sym_pop(&global_stack, NULL);
1012
    sym_pop(&local_stack, NULL);
1013
 
1014
    return s1->nb_errors != 0 ? -1 : 0;
1015
}
1016
 
1017
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
1018
{
1019
    int len, ret;
1020
 
1021
    len = strlen(str);
1022
    tcc_open_bf(s, "", len);
1023
    memcpy(file->buffer, str, len);
1024
    ret = tcc_compile(s);
1025
    tcc_close();
1026
    return ret;
1027
}
1028
 
1029
/* define a preprocessor symbol. A value can also be provided with the '=' operator */
1030
LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value)
1031
{
1032
    int len1, len2;
1033
    /* default value */
1034
    if (!value)
1035
        value = "1";
1036
    len1 = strlen(sym);
1037
    len2 = strlen(value);
1038
 
1039
    /* init file structure */
1040
    tcc_open_bf(s1, "", len1 + len2 + 1);
1041
    memcpy(file->buffer, sym, len1);
1042
    file->buffer[len1] = ' ';
1043
    memcpy(file->buffer + len1 + 1, value, len2);
1044
 
1045
    /* parse with define parser */
1046
    ch = file->buf_ptr[0];
1047
    next_nomacro();
1048
    parse_define();
1049
 
1050
    tcc_close();
1051
}
1052
 
1053
/* undefine a preprocessor symbol */
1054
LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym)
1055
{
1056
    TokenSym *ts;
1057
    Sym *s;
1058
    ts = tok_alloc(sym, strlen(sym));
1059
    s = define_find(ts->tok);
1060
    /* undefine symbol by putting an invalid name */
1061
    if (s)
1062
        define_undef(s);
1063
}
1064
 
1065
/* cleanup all static data used during compilation */
1066
static void tcc_cleanup(void)
1067
{
1068
    if (NULL == tcc_state)
1069
        return;
1070
    tcc_state = NULL;
1071
 
1072
    preprocess_delete();
1073
 
1074
    /* free sym_pools */
1075
    dynarray_reset(&sym_pools, &nb_sym_pools);
1076
    /* reset symbol stack */
1077
    sym_free_first = NULL;
1078
}
1079
 
1080
LIBTCCAPI TCCState *tcc_new(void)
1081
{
1082
    TCCState *s;
1083
    char buffer[100];
1084
    int a,b,c;
1085
 
1086
    tcc_cleanup();
1087
 
1088
    s = tcc_mallocz(sizeof(TCCState));
1089
    if (!s)
1090
        return NULL;
1091
    tcc_state = s;
1092
#ifdef _WIN32
1093
    tcc_set_lib_path_w32(s);
1094
#else
7520 siemargl 1095
#ifdef TCC_TARGET_MEOS
1096
    tcc_set_lib_path_kos(s);
1097
#else
6429 siemargl 1098
    tcc_set_lib_path(s, CONFIG_TCCDIR);
1099
#endif
7520 siemargl 1100
#endif
6429 siemargl 1101
    s->output_type = 0;
1102
    preprocess_new();
1103
    s->include_stack_ptr = s->include_stack;
1104
 
1105
    /* we add dummy defines for some special macros to speed up tests
1106
       and to have working defined() */
1107
    define_push(TOK___LINE__, MACRO_OBJ, NULL, NULL);
1108
    define_push(TOK___FILE__, MACRO_OBJ, NULL, NULL);
1109
    define_push(TOK___DATE__, MACRO_OBJ, NULL, NULL);
1110
    define_push(TOK___TIME__, MACRO_OBJ, NULL, NULL);
1111
 
1112
    /* define __TINYC__ 92X  */
1113
    sscanf(TCC_VERSION, "%d.%d.%d", &a, &b, &c);
1114
    sprintf(buffer, "%d", a*10000 + b*100 + c);
1115
    tcc_define_symbol(s, "__TINYC__", buffer);
1116
 
1117
    /* standard defines */
1118
    tcc_define_symbol(s, "__STDC__", NULL);
1119
    tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
1120
    tcc_define_symbol(s, "__STDC_HOSTED__", NULL);
1121
 
1122
    /* target defines */
1123
#if defined(TCC_TARGET_I386)
1124
    tcc_define_symbol(s, "__i386__", NULL);
1125
    tcc_define_symbol(s, "__i386", NULL);
1126
    tcc_define_symbol(s, "i386", NULL);
1127
#elif defined(TCC_TARGET_X86_64)
1128
    tcc_define_symbol(s, "__x86_64__", NULL);
1129
#elif defined(TCC_TARGET_ARM)
1130
    tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
1131
    tcc_define_symbol(s, "__arm_elf__", NULL);
1132
    tcc_define_symbol(s, "__arm_elf", NULL);
1133
    tcc_define_symbol(s, "arm_elf", NULL);
1134
    tcc_define_symbol(s, "__arm__", NULL);
1135
    tcc_define_symbol(s, "__arm", NULL);
1136
    tcc_define_symbol(s, "arm", NULL);
1137
    tcc_define_symbol(s, "__APCS_32__", NULL);
1138
    tcc_define_symbol(s, "__ARMEL__", NULL);
1139
#if defined(TCC_ARM_EABI)
1140
    tcc_define_symbol(s, "__ARM_EABI__", NULL);
1141
#endif
1142
#if defined(TCC_ARM_HARDFLOAT)
1143
    s->float_abi = ARM_HARD_FLOAT;
1144
    tcc_define_symbol(s, "__ARM_PCS_VFP", NULL);
1145
#else
1146
    s->float_abi = ARM_SOFTFP_FLOAT;
1147
#endif
1148
#elif defined(TCC_TARGET_ARM64)
1149
    tcc_define_symbol(s, "__aarch64__", NULL);
1150
#endif
1151
 
1152
#ifdef TCC_TARGET_PE
1153
    tcc_define_symbol(s, "_WIN32", NULL);
1154
# ifdef TCC_TARGET_X86_64
1155
    tcc_define_symbol(s, "_WIN64", NULL);
1156
# endif
1157
#else
1158
    tcc_define_symbol(s, "__unix__", NULL);
1159
    tcc_define_symbol(s, "__unix", NULL);
1160
    tcc_define_symbol(s, "unix", NULL);
1161
# if defined(__linux__)
1162
    tcc_define_symbol(s, "__linux__", NULL);
1163
    tcc_define_symbol(s, "__linux", NULL);
1164
# endif
1165
# if defined(__FreeBSD__)
1166
#  define str(s) #s
1167
    tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__));
1168
#  undef str
1169
# endif
1170
# if defined(__FreeBSD_kernel__)
1171
    tcc_define_symbol(s, "__FreeBSD_kernel__", NULL);
1172
# endif
1173
#endif
1174
# if defined(__NetBSD__)
1175
#  define str(s) #s
1176
    tcc_define_symbol(s, "__NetBSD__", str( __NetBSD__));
1177
#  undef str
1178
# endif
1179
 
1180
    /* TinyCC & gcc defines */
1181
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
1182
    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long long");
1183
    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long long");
1184
#else
1185
    tcc_define_symbol(s, "__SIZE_TYPE__", "unsigned long");
1186
    tcc_define_symbol(s, "__PTRDIFF_TYPE__", "long");
1187
#endif
1188
 
1189
#ifdef TCC_TARGET_PE
1190
    tcc_define_symbol(s, "__WCHAR_TYPE__", "unsigned short");
1191
    tcc_define_symbol(s, "__WINT_TYPE__", "unsigned short");
1192
#else
1193
    tcc_define_symbol(s, "__WCHAR_TYPE__", "int");
1194
    /* wint_t is unsigned int by default, but (signed) int on BSDs
1195
       and unsigned short on windows.  Other OSes might have still
1196
       other conventions, sigh.  */
1197
#if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__)
1198
    tcc_define_symbol(s, "__WINT_TYPE__", "int");
1199
#else
1200
    tcc_define_symbol(s, "__WINT_TYPE__", "unsigned int");
1201
#endif
1202
#endif
1203
 
1204
#ifndef TCC_TARGET_PE
1205
    /* glibc defines */
1206
    tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)");
1207
    tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW");
1208
    /* paths for crt objects */
1209
    tcc_split_path(s, (void ***)&s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
1210
#endif
1211
 
1212
    /* no section zero */
1213
    dynarray_add((void ***)&s->sections, &s->nb_sections, NULL);
1214
 
1215
    /* create standard sections */
1216
    text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1217
    data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1218
    bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
1219
 
1220
    /* symbols are always generated for linking stage */
1221
    symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
1222
                                ".strtab",
1223
                                ".hashtab", SHF_PRIVATE);
1224
    strtab_section = symtab_section->link;
1225
    s->symtab = symtab_section;
1226
 
1227
    /* private symbol table for dynamic symbols */
1228
    s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
1229
                                      ".dynstrtab",
1230
                                      ".dynhashtab", SHF_PRIVATE);
1231
    s->alacarte_link = 1;
1232
    s->nocommon = 1;
1233
    s->warn_implicit_function_declaration = 1;
1234
 
1235
#ifdef CHAR_IS_UNSIGNED
1236
    s->char_is_unsigned = 1;
1237
#endif
1238
    /* enable this if you want symbols with leading underscore on windows: */
1239
#if 0 /* def TCC_TARGET_PE */
1240
    s->leading_underscore = 1;
1241
#endif
1242
#if 0 /* TCC_TARGET_MEOS */
1243
    s->leading_underscore = 1;
1244
#endif
1245
#ifdef TCC_TARGET_I386
1246
    s->seg_size = 32;
1247
#endif
1248
#ifdef TCC_IS_NATIVE
1249
    s->runtime_main = "main";
1250
#endif
1251
    return s;
1252
}
1253
 
1254
LIBTCCAPI void tcc_delete(TCCState *s1)
1255
{
1256
    int i;
1257
    int bench = s1->do_bench;
1258
 
1259
    tcc_cleanup();
1260
 
1261
    /* close a preprocessor output */
1262
    if (s1->ppfp && s1->ppfp != stdout)
1263
        fclose(s1->ppfp);
1264
    if (s1->dffp && s1->dffp != s1->ppfp)
1265
        fclose(s1->dffp);
1266
 
1267
    /* free all sections */
1268
    for(i = 1; i < s1->nb_sections; i++)
1269
        free_section(s1->sections[i]);
1270
    dynarray_reset(&s1->sections, &s1->nb_sections);
1271
 
1272
    for(i = 0; i < s1->nb_priv_sections; i++)
1273
        free_section(s1->priv_sections[i]);
1274
    dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
1275
 
1276
    /* free any loaded DLLs */
1277
#ifdef TCC_IS_NATIVE
1278
    for ( i = 0; i < s1->nb_loaded_dlls; i++) {
1279
        DLLReference *ref = s1->loaded_dlls[i];
1280
        if ( ref->handle )
1281
            dlclose(ref->handle);
1282
    }
1283
#endif
1284
 
1285
    /* free loaded dlls array */
1286
    dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
1287
 
1288
    /* free library paths */
1289
    dynarray_reset(&s1->library_paths, &s1->nb_library_paths);
1290
    dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths);
1291
 
1292
    /* free include paths */
1293
    dynarray_reset(&s1->cached_includes, &s1->nb_cached_includes);
1294
    dynarray_reset(&s1->include_paths, &s1->nb_include_paths);
1295
    dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths);
1296
 
1297
    tcc_free(s1->tcc_lib_path);
1298
    tcc_free(s1->soname);
1299
    tcc_free(s1->rpath);
1300
    tcc_free(s1->init_symbol);
1301
    tcc_free(s1->fini_symbol);
1302
    tcc_free(s1->outfile);
1303
    tcc_free(s1->deps_outfile);
1304
    dynarray_reset(&s1->files, &s1->nb_files);
1305
    dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
1306
    dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
1307
 
1308
#ifdef TCC_IS_NATIVE
1309
# ifdef HAVE_SELINUX
1310
    munmap (s1->write_mem, s1->mem_size);
1311
    munmap (s1->runtime_mem, s1->mem_size);
1312
# else
1313
    tcc_free(s1->runtime_mem);
1314
# endif
1315
#endif
1316
 
1317
    tcc_free(s1->sym_attrs);
1318
    tcc_free(s1);
1319
    tcc_memstats(bench);
1320
}
1321
 
1322
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
1323
{
1324
    tcc_split_path(s, (void ***)&s->include_paths, &s->nb_include_paths, pathname);
1325
    return 0;
1326
}
1327
 
1328
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname)
1329
{
1330
    tcc_split_path(s, (void ***)&s->sysinclude_paths, &s->nb_sysinclude_paths, pathname);
1331
    return 0;
1332
}
1333
 
1334
ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags, int filetype)
1335
{
1336
    ElfW(Ehdr) ehdr;
1337
    int fd, ret, size;
1338
 
1339
    parse_flags = 0;
1340
#ifdef CONFIG_TCC_ASM
1341
    /* if .S file, define __ASSEMBLER__ like gcc does */
1342
    if ((filetype == TCC_FILETYPE_ASM) || (filetype == TCC_FILETYPE_ASM_PP)) {
1343
        tcc_define_symbol(s1, "__ASSEMBLER__", NULL);
1344
        parse_flags = PARSE_FLAG_ASM_FILE;
1345
    }
1346
#endif
1347
 
1348
    /* open the file */
1349
    ret = tcc_open(s1, filename);
1350
    if (ret < 0) {
1351
        if (flags & AFF_PRINT_ERROR)
1352
            tcc_error_noabort("file '%s' not found", filename);
1353
        return ret;
1354
    }
1355
 
1356
    /* update target deps */
1357
    dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps,
1358
            tcc_strdup(filename));
1359
 
1360
    if (flags & AFF_PREPROCESS) {
1361
        ret = tcc_preprocess(s1);
1362
        goto the_end;
1363
    }
1364
 
1365
    if (filetype == TCC_FILETYPE_C) {
1366
        /* C file assumed */
1367
        ret = tcc_compile(s1);
1368
        goto the_end;
1369
    }
1370
 
1371
#ifdef CONFIG_TCC_ASM
1372
    if (filetype == TCC_FILETYPE_ASM_PP) {
1373
        /* non preprocessed assembler */
1374
        ret = tcc_assemble(s1, 1);
1375
        goto the_end;
1376
    }
1377
 
1378
    if (filetype == TCC_FILETYPE_ASM) {
1379
        /* preprocessed assembler */
1380
        ret = tcc_assemble(s1, 0);
1381
        goto the_end;
1382
    }
1383
#endif
1384
 
1385
    fd = file->fd;
1386
    /* assume executable format: auto guess file type */
1387
    size = read(fd, &ehdr, sizeof(ehdr));
1388
    lseek(fd, 0, SEEK_SET);
1389
    if (size <= 0) {
1390
        tcc_error_noabort("could not read header");
1391
        goto the_end;
1392
    }
1393
 
1394
    if (size == sizeof(ehdr) &&
1395
        ehdr.e_ident[0] == ELFMAG0 &&
1396
        ehdr.e_ident[1] == ELFMAG1 &&
1397
        ehdr.e_ident[2] == ELFMAG2 &&
1398
        ehdr.e_ident[3] == ELFMAG3) {
1399
 
1400
        /* do not display line number if error */
1401
        file->line_num = 0;
1402
        if (ehdr.e_type == ET_REL) {
1403
            ret = tcc_load_object_file(s1, fd, 0);
1404
            goto the_end;
1405
 
1406
        }
1407
#if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS)
1408
        if (ehdr.e_type == ET_DYN) {
1409
            if (s1->output_type == TCC_OUTPUT_MEMORY) {
1410
#ifdef TCC_IS_NATIVE
1411
                void *h;
1412
                h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
1413
                if (h)
1414
#endif
1415
                    ret = 0;
1416
            } else {
1417
                ret = tcc_load_dll(s1, fd, filename,
1418
                                   (flags & AFF_REFERENCED_DLL) != 0);
1419
            }
1420
            goto the_end;
1421
        }
1422
#endif
1423
        tcc_error_noabort("unrecognized ELF file");
1424
        goto the_end;
1425
    }
1426
 
1427
    if (memcmp((char *)&ehdr, ARMAG, 8) == 0) {
1428
        file->line_num = 0; /* do not display line number if error */
1429
        ret = tcc_load_archive(s1, fd);
1430
        goto the_end;
1431
    }
1432
 
1433
#ifdef TCC_TARGET_COFF
1434
    if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) {
1435
        ret = tcc_load_coff(s1, fd);
1436
        goto the_end;
1437
    }
1438
#endif
1439
 
1440
#if defined(TCC_TARGET_PE) ||  defined(TCC_TARGET_MEOS)
1441
    ret = pe_load_file(s1, filename, fd);
1442
#else
1443
    /* as GNU ld, consider it is an ld script if not recognized */
1444
    ret = tcc_load_ldscript(s1);
1445
#endif
1446
    if (ret < 0)
1447
        tcc_error_noabort("unrecognized file type");
1448
 
1449
the_end:
1450
    tcc_close();
1451
    return ret;
1452
}
1453
 
1454
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename, int filetype)
1455
{
1456
    if (s->output_type == TCC_OUTPUT_PREPROCESS)
1457
        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR | AFF_PREPROCESS, filetype);
1458
    else
1459
        return tcc_add_file_internal(s, filename, AFF_PRINT_ERROR, filetype);
1460
}
1461
 
1462
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
1463
{
1464
    tcc_split_path(s, (void ***)&s->library_paths, &s->nb_library_paths, pathname);
1465
    return 0;
1466
}
1467
 
1468
static int tcc_add_library_internal(TCCState *s, const char *fmt,
1469
    const char *filename, int flags, char **paths, int nb_paths)
1470
{
1471
    char buf[1024];
1472
    int i;
1473
 
1474
    for(i = 0; i < nb_paths; i++) {
1475
        snprintf(buf, sizeof(buf), fmt, paths[i], filename);
7520 siemargl 1476
//printf("tcc_add_library_internal::added lib [%s]\n", buf);
6429 siemargl 1477
        if (tcc_add_file_internal(s, buf, flags, TCC_FILETYPE_BINARY) == 0)
1478
            return 0;
1479
    }
1480
    return -1;
1481
}
1482
 
1483
#if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS)
1484
/* find and load a dll. Return non zero if not found */
1485
/* XXX: add '-rpath' option support ? */
1486
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags)
1487
{
1488
    return tcc_add_library_internal(s, "%s/%s", filename, flags,
1489
        s->library_paths, s->nb_library_paths);
1490
}
1491
#endif
1492
 
1493
ST_FUNC int tcc_add_crt(TCCState *s, const char *filename)
1494
{
1495
    if (-1 == tcc_add_library_internal(s, "%s/%s",
1496
        filename, 0, s->crt_paths, s->nb_crt_paths))
1497
        tcc_error_noabort("file '%s' not found", filename);
1498
    return 0;
1499
}
1500
 
1501
/* the library name is the same as the argument of the '-l' option */
1502
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
1503
{
1504
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS)
1505
    const char *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL };
1506
    const char **pp = s->static_link ? libs + 4 : libs;
1507
#else
1508
    const char *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
1509
    const char **pp = s->static_link ? libs + 1 : libs;
1510
#endif
1511
    while (*pp) {
1512
        if (0 == tcc_add_library_internal(s, *pp,
1513
            libraryname, 0, s->library_paths, s->nb_library_paths))
1514
            return 0;
1515
        ++pp;
1516
    }
1517
    return -1;
1518
}
1519
 
1520
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *libname)
1521
{
1522
    int ret = tcc_add_library(s, libname);
1523
    if (ret < 0)
1524
        tcc_error_noabort("cannot find library 'lib%s'", libname);
1525
    return ret;
1526
}
1527
 
1528
/* habdle #pragma comment(lib,) */
1529
ST_FUNC void tcc_add_pragma_libs(TCCState *s1)
1530
{
1531
    int i;
1532
    for (i = 0; i < s1->nb_pragma_libs; i++)
1533
        tcc_add_library_err(s1, s1->pragma_libs[i]);
1534
}
1535
 
1536
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val)
1537
{
1538
#if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS)
1539
    /* On x86_64 'val' might not be reachable with a 32bit offset.
1540
       So it is handled here as if it were in a DLL. */
1541
    pe_putimport(s, 0, name, (uintptr_t)val);
1542
#else
1543
    add_elf_sym(symtab_section, (uintptr_t)val, 0,
1544
        ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
1545
        SHN_ABS, name);
1546
#endif
1547
    return 0;
1548
}
1549
 
1550
 
1551
/* Windows stat* ( https://msdn.microsoft.com/en-us/library/14h5k7ff.aspx ):
1552
 * - st_gid, st_ino, st_uid: only valid on "unix" file systems (not FAT, NTFS, etc)
1553
 * - st_atime, st_ctime: not valid on FAT, valid on NTFS.
1554
 * - Other fields should be reasonably compatible (and S_ISDIR should work).
1555
 *
1556
 * BY_HANDLE_FILE_INFORMATION ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788%28v=vs.85%29.aspx ):
1557
 * - File index (combined nFileIndexHigh and nFileIndexLow) _may_ change when the file is opened.
1558
 *   - But on NTFS: it's guaranteed to be the same value until the file is deleted.
1559
 * - On windows server 2012 there's a 128b file id, and the 64b one via
1560
 *   nFileIndex* is not guaranteed to be unique.
1561
 *
1562
 * - MS Docs suggest to that volume number with the file index could be used to
1563
 *   check if two handles refer to the same file.
1564
 */
1565
#ifndef _WIN32
1566
typedef struct stat                file_info_t;
1567
#else
1568
typedef BY_HANDLE_FILE_INFORMATION file_info_t;
1569
#endif
1570
 
1571
int get_file_info(const char *fname, file_info_t *out_info)
1572
{
1573
#ifndef _WIN32
1574
    return stat(fname, out_info);
1575
#else
1576
    int rv = 1;
1577
    HANDLE h = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
1578
                          FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, NULL);
1579
 
1580
    if (h != INVALID_HANDLE_VALUE) {
1581
        rv = !GetFileInformationByHandle(h, out_info);
1582
        CloseHandle(h);
1583
    }
1584
    return rv;
1585
#endif
1586
}
1587
 
1588
int is_dir(file_info_t *info)
1589
{
1590
#ifndef _WIN32
1591
    return S_ISDIR(info->st_mode);
1592
#else
1593
    return (info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ==
1594
           FILE_ATTRIBUTE_DIRECTORY;
1595
#endif
1596
}
1597
 
1598
int is_same_file(const file_info_t *fi1, const file_info_t *fi2)
1599
{
1600
#ifndef _WIN32
1601
    return fi1->st_dev == fi2->st_dev &&
1602
           fi1->st_ino == fi2->st_ino;
1603
#else
1604
    return fi1->dwVolumeSerialNumber == fi2->dwVolumeSerialNumber &&
1605
           fi1->nFileIndexHigh       == fi2->nFileIndexHigh &&
1606
           fi1->nFileIndexLow        == fi2->nFileIndexLow;
1607
#endif
1608
}
1609
 
1610
static void
1611
tcc_normalize_inc_dirs_aux(file_info_t *stats, size_t *pnum, char **path)
1612
{
1613
    size_t i, num = *pnum;
1614
    if (get_file_info(*path, &stats[num]) || !is_dir(&stats[num]))
1615
        goto remove;
1616
    for (i = 0; i < num; i++)
1617
        if (is_same_file(&stats[i], &stats[num]))
1618
            goto remove;
1619
    *pnum = num + 1;
1620
    return;
1621
 remove:
1622
    tcc_free(*path);
1623
    *path = 0;
1624
}
1625
 
1626
/* Remove non-existent and duplicate directories from include paths. */
1627
ST_FUNC void tcc_normalize_inc_dirs(TCCState *s)
1628
{
1629
    file_info_t *stats =
1630
        tcc_malloc(((size_t)s->nb_sysinclude_paths + s->nb_include_paths) *
1631
                   sizeof(*stats));
1632
    size_t i, num = 0;
1633
    for (i = 0; i < s->nb_sysinclude_paths; i++)
1634
        tcc_normalize_inc_dirs_aux(stats, &num, &s->sysinclude_paths[i]);
1635
    for (i = 0; i < s->nb_include_paths; i++)
1636
        tcc_normalize_inc_dirs_aux(stats, &num, &s->include_paths[i]);
1637
    tcc_free(stats);
1638
}
1639
 
1640
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
1641
{
1642
    s->output_type = output_type;
1643
 
1644
    if (s->output_type == TCC_OUTPUT_PREPROCESS) {
1645
        if (!s->outfile) {
1646
            s->ppfp = stdout;
1647
        } else {
1648
            s->ppfp = fopen(s->outfile, "w");
1649
            if (!s->ppfp)
1650
                tcc_error("could not write '%s'", s->outfile);
1651
        }
1652
        s->dffp = s->ppfp;
1653
        if (s->dflag == 'M')
1654
            s->ppfp = NULL;
1655
    }
1656
    if (s->option_C && !s->ppfp)
1657
        s->option_C = 0;
1658
 
1659
    if (!s->nostdinc) {
1660
        /* default include paths */
1661
        /* -isystem paths have already been handled */
1662
        tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS);
1663
    }
1664
 
1665
    /* if bound checking, then add corresponding sections */
1666
#ifdef CONFIG_TCC_BCHECK
1667
    if (s->do_bounds_check) {
1668
        /* define symbol */
1669
        tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
1670
        /* create bounds sections */
1671
        bounds_section = new_section(s, ".bounds",
1672
                                     SHT_PROGBITS, SHF_ALLOC);
1673
        lbounds_section = new_section(s, ".lbounds",
1674
                                      SHT_PROGBITS, SHF_ALLOC);
1675
    }
1676
#endif
1677
 
1678
    if (s->char_is_unsigned) {
1679
        tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
1680
    }
1681
 
1682
    /* add debug sections */
1683
    if (s->do_debug) {
1684
        /* stab symbols */
1685
        stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
1686
        stab_section->sh_entsize = sizeof(Stab_Sym);
1687
        stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
1688
        put_elf_str(stabstr_section, "");
1689
        stab_section->link = stabstr_section;
1690
        /* put first entry */
1691
        put_stabs("", 0, 0, 0, 0);
1692
    }
1693
 
1694
    tcc_add_library_path(s, CONFIG_TCC_LIBPATHS);
1695
#ifdef TCC_TARGET_PE
1696
# ifdef _WIN32
1697
    tcc_add_systemdir(s);
1698
# endif
1699
#elif defined(TCC_TARGET_MEOS)
1700
    if (s->output_type != TCC_OUTPUT_OBJ && !s->nostdlib)
1701
    {
1702
        tcc_add_crt(s,"start.o");
1703
//        tcc_add_library(s,"ck"); // adding libck.a dont work, because need to be added last
1704
    }
1705
#else
1706
    /* add libc crt1/crti objects */
1707
    if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) &&
1708
        !s->nostdlib) {
1709
        if (output_type != TCC_OUTPUT_DLL)
1710
            tcc_add_crt(s, "crt1.o");
1711
        tcc_add_crt(s, "crti.o");
1712
    }
1713
#endif
1714
 
1715
#ifdef CONFIG_TCC_BCHECK
1716
    if (s->do_bounds_check && (output_type == TCC_OUTPUT_EXE))
1717
    {
1718
        /* force a bcheck.o linking */
1719
        addr_t func = TOK___bound_init;
1720
        Sym *sym = external_global_sym(func, &func_old_type, 0);
1721
        if (!sym->c)
1722
            put_extern_sym(sym, NULL, 0, 0);
1723
    }
1724
#endif
1725
 
1726
    if (s->normalize_inc_dirs)
1727
        tcc_normalize_inc_dirs(s);
1728
    if (s->output_type == TCC_OUTPUT_PREPROCESS)
1729
        print_defines();
1730
 
1731
    return 0;
1732
}
1733
 
1734
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
1735
{
1736
    tcc_free(s->tcc_lib_path);
1737
    s->tcc_lib_path = tcc_strdup(path);
1738
}
1739
 
1740
#define WD_ALL    0x0001 /* warning is activated when using -Wall */
1741
#define FD_INVERT 0x0002 /* invert value before storing */
1742
 
1743
typedef struct FlagDef {
1744
    uint16_t offset;
1745
    uint16_t flags;
1746
    const char *name;
1747
} FlagDef;
1748
 
1749
static const FlagDef warning_defs[] = {
1750
    { offsetof(TCCState, warn_unsupported), 0, "unsupported" },
1751
    { offsetof(TCCState, warn_write_strings), 0, "write-strings" },
1752
    { offsetof(TCCState, warn_error), 0, "error" },
1753
    { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL,
1754
      "implicit-function-declaration" },
1755
};
1756
 
1757
ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags,
1758
                    const char *name, int value)
1759
{
1760
    int i;
1761
    const FlagDef *p;
1762
    const char *r;
1763
 
1764
    r = name;
1765
    if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') {
1766
        r += 3;
1767
        value = !value;
1768
    }
1769
    for(i = 0, p = flags; i < nb_flags; i++, p++) {
1770
        if (!strcmp(r, p->name))
1771
            goto found;
1772
    }
1773
    return -1;
1774
 found:
1775
    if (p->flags & FD_INVERT)
1776
        value = !value;
1777
    *(int *)((uint8_t *)s + p->offset) = value;
1778
    return 0;
1779
}
1780
 
1781
/* set/reset a warning */
1782
static int tcc_set_warning(TCCState *s, const char *warning_name, int value)
1783
{
1784
    int i;
1785
    const FlagDef *p;
1786
 
1787
    if (!strcmp(warning_name, "all")) {
1788
        for(i = 0, p = warning_defs; i < countof(warning_defs); i++, p++) {
1789
            if (p->flags & WD_ALL)
1790
                *(int *)((uint8_t *)s + p->offset) = 1;
1791
        }
1792
		s->warn_unsupported = 1;  // siemargl. was unused flag about compiler features
1793
        return 0;
1794
    } else {
1795
        return set_flag(s, warning_defs, countof(warning_defs),
1796
                        warning_name, value);
1797
    }
1798
}
1799
 
1800
static const FlagDef flag_defs[] = {
1801
    { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
1802
    { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
1803
    { offsetof(TCCState, nocommon), FD_INVERT, "common" },
1804
    { offsetof(TCCState, leading_underscore), 0, "leading-underscore" },
1805
    { offsetof(TCCState, ms_extensions), 0, "ms-extensions" },
1806
    { offsetof(TCCState, old_struct_init_code), 0, "old-struct-init-code" },
1807
    { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" },
1808
    { offsetof(TCCState, normalize_inc_dirs), 0, "normalize-inc-dirs" },
1809
};
1810
 
1811
/* set/reset a flag */
1812
static int tcc_set_flag(TCCState *s, const char *flag_name, int value)
1813
{
1814
    return set_flag(s, flag_defs, countof(flag_defs),
1815
                    flag_name, value);
1816
}
1817
 
1818
 
1819
static int strstart(const char *val, const char **str)
1820
{
1821
    const char *p, *q;
1822
    p = *str;
1823
    q = val;
1824
    while (*q) {
1825
        if (*p != *q)
1826
            return 0;
1827
        p++;
1828
        q++;
1829
    }
1830
    *str = p;
1831
    return 1;
1832
}
1833
 
1834
/* Like strstart, but automatically takes into account that ld options can
1835
 *
1836
 * - start with double or single dash (e.g. '--soname' or '-soname')
1837
 * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
1838
 *   or '-Wl,-soname=x.so')
1839
 *
1840
 * you provide `val` always in 'option[=]' form (no leading -)
1841
 */
1842
static int link_option(const char *str, const char *val, const char **ptr)
1843
{
1844
    const char *p, *q;
1845
 
1846
    /* there should be 1 or 2 dashes */
1847
    if (*str++ != '-')
1848
        return 0;
1849
    if (*str == '-')
1850
        str++;
1851
 
1852
    /* then str & val should match (potentialy up to '=') */
1853
    p = str;
1854
    q = val;
1855
 
1856
    while (*q != '\0' && *q != '=') {
1857
        if (*p != *q)
1858
            return 0;
1859
        p++;
1860
        q++;
1861
    }
1862
 
1863
    /* '=' near eos means ',' or '=' is ok */
1864
    if (*q == '=') {
1865
        if (*p != ',' && *p != '=')
1866
            return 0;
1867
        p++;
1868
        q++;
1869
    }
1870
 
1871
    if (ptr)
1872
        *ptr = p;
1873
    return 1;
1874
}
1875
 
1876
static const char *skip_linker_arg(const char **str)
1877
{
1878
    const char *s1 = *str;
1879
    const char *s2 = strchr(s1, ',');
1880
    *str = s2 ? s2++ : (s2 = s1 + strlen(s1));
1881
    return s2;
1882
}
1883
 
1884
static char *copy_linker_arg(const char *p)
1885
{
1886
    const char *q = p;
1887
    skip_linker_arg(&q);
1888
    return pstrncpy(tcc_malloc(q - p + 1), p, q - p);
1889
}
1890
 
1891
/* set linker options */
1892
static int tcc_set_linker(TCCState *s, const char *option)
6441 siemargl 1893
{
6429 siemargl 1894
    while (option && *option) {
1895
 
1896
        const char *p = option;
1897
        char *end = NULL;
1898
        int ignoring = 0;
1899
 
1900
        if (link_option(option, "Bsymbolic", &p)) {
1901
            s->symbolic = 1;
1902
        } else if (link_option(option, "nostdlib", &p)) {
1903
            s->nostdlib = 1;
1904
        } else if (link_option(option, "fini=", &p)) {
1905
            s->fini_symbol = copy_linker_arg(p);
1906
            ignoring = 1;
1907
        } else if (link_option(option, "image-base=", &p)
1908
                || link_option(option, "Ttext=", &p)) {
1909
            s->text_addr = strtoull(p, &end, 16);
1910
            s->has_text_addr = 1;
1911
        } else if (link_option(option, "init=", &p)) {
1912
            s->init_symbol = copy_linker_arg(p);
1913
            ignoring = 1;
1914
        } else if (link_option(option, "oformat=", &p)) {
1915
#if defined(TCC_TARGET_PE)
1916
            if (strstart("pe-", &p)) {
1917
#elif defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
1918
            if (strstart("elf64-", &p)) {
1919
#else
1920
            if (strstart("elf32-", &p)) {
1921
#endif
1922
                s->output_format = TCC_OUTPUT_FORMAT_ELF;
1923
            } else if (!strcmp(p, "binary")) {
1924
                s->output_format = TCC_OUTPUT_FORMAT_BINARY;
1925
#ifdef TCC_TARGET_COFF
1926
            } else if (!strcmp(p, "coff")) {
1927
                s->output_format = TCC_OUTPUT_FORMAT_COFF;
1928
#endif
1929
            } else
1930
                goto err;
1931
 
1932
        } else if (link_option(option, "as-needed", &p)) {
1933
            ignoring = 1;
1934
        } else if (link_option(option, "O", &p)) {
1935
            ignoring = 1;
1936
        } else if (link_option(option, "rpath=", &p)) {
1937
            s->rpath = copy_linker_arg(p);
1938
        } else if (link_option(option, "section-alignment=", &p)) {
1939
            s->section_align = strtoul(p, &end, 16);
1940
        } else if (link_option(option, "soname=", &p)) {
1941
            s->soname = copy_linker_arg(p);
1942
#ifdef TCC_TARGET_PE
1943
        } else if (link_option(option, "file-alignment=", &p)) {
1944
            s->pe_file_align = strtoul(p, &end, 16);
1945
        } else if (link_option(option, "stack=", &p)) {
1946
            s->pe_stack_size = strtoul(p, &end, 10);
1947
        } else if (link_option(option, "subsystem=", &p)) {
1948
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
1949
            if (!strcmp(p, "native")) {
1950
                s->pe_subsystem = 1;
1951
            } else if (!strcmp(p, "console")) {
1952
                s->pe_subsystem = 3;
1953
            } else if (!strcmp(p, "gui")) {
1954
                s->pe_subsystem = 2;
1955
            } else if (!strcmp(p, "posix")) {
1956
                s->pe_subsystem = 7;
1957
            } else if (!strcmp(p, "efiapp")) {
1958
                s->pe_subsystem = 10;
1959
            } else if (!strcmp(p, "efiboot")) {
1960
                s->pe_subsystem = 11;
1961
            } else if (!strcmp(p, "efiruntime")) {
1962
                s->pe_subsystem = 12;
1963
            } else if (!strcmp(p, "efirom")) {
1964
                s->pe_subsystem = 13;
1965
#elif defined(TCC_TARGET_ARM)
1966
            if (!strcmp(p, "wince")) {
1967
                s->pe_subsystem = 9;
1968
#endif
1969
            } else
1970
                goto err;
1971
#endif
1972
        } else
1973
            goto err;
1974
 
1975
        if (ignoring && s->warn_unsupported) err: {
1976
            char buf[100], *e;
1977
            pstrcpy(buf, sizeof buf, e = copy_linker_arg(option)), tcc_free(e);
1978
            if (ignoring)
1979
                tcc_warning("unsupported linker option '%s'", buf);
1980
            else
1981
                tcc_error("unsupported linker option '%s'", buf);
1982
        }
1983
        option = skip_linker_arg(&p);
1984
    }
1985
    return 0;
1986
}
1987
 
1988
typedef struct TCCOption {
1989
    const char *name;
1990
    uint16_t index;
1991
    uint16_t flags;
1992
} TCCOption;
1993
 
1994
enum {
1995
    TCC_OPTION_HELP,
1996
    TCC_OPTION_I,
1997
    TCC_OPTION_D,
1998
    TCC_OPTION_U,
1999
    TCC_OPTION_P,
2000
    TCC_OPTION_L,
2001
    TCC_OPTION_B,
2002
    TCC_OPTION_l,
2003
    TCC_OPTION_bench,
2004
    TCC_OPTION_bt,
2005
    TCC_OPTION_b,
2006
    TCC_OPTION_g,
2007
    TCC_OPTION_c,
2008
    TCC_OPTION_C,
2009
    TCC_OPTION_dumpversion,
2010
    TCC_OPTION_d,
2011
    TCC_OPTION_float_abi,
2012
    TCC_OPTION_static,
2013
    TCC_OPTION_std,
2014
    TCC_OPTION_shared,
2015
    TCC_OPTION_soname,
2016
    TCC_OPTION_o,
2017
    TCC_OPTION_r,
2018
    TCC_OPTION_s,
2019
    TCC_OPTION_traditional,
2020
    TCC_OPTION_Wl,
2021
    TCC_OPTION_W,
2022
    TCC_OPTION_O,
2023
    TCC_OPTION_m,
2024
    TCC_OPTION_f,
2025
    TCC_OPTION_isystem,
2026
    TCC_OPTION_iwithprefix,
2027
    TCC_OPTION_nostdinc,
2028
    TCC_OPTION_nostdlib,
2029
    TCC_OPTION_print_search_dirs,
2030
    TCC_OPTION_rdynamic,
2031
    TCC_OPTION_pedantic,
2032
    TCC_OPTION_pthread,
2033
    TCC_OPTION_run,
2034
    TCC_OPTION_v,
2035
    TCC_OPTION_w,
2036
    TCC_OPTION_pipe,
2037
    TCC_OPTION_E,
2038
    TCC_OPTION_MD,
2039
    TCC_OPTION_MF,
6441 siemargl 2040
    TCC_OPTION_x,
2041
    TCC_OPTION_stack
6429 siemargl 2042
};
2043
 
2044
#define TCC_OPTION_HAS_ARG 0x0001
2045
#define TCC_OPTION_NOSEP   0x0002 /* cannot have space before option and arg */
2046
 
2047
static const TCCOption tcc_options[] = {
2048
    { "h", TCC_OPTION_HELP, 0 },
2049
    { "-help", TCC_OPTION_HELP, 0 },
2050
    { "?", TCC_OPTION_HELP, 0 },
2051
    { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG },
2052
    { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG },
2053
    { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG },
2054
    { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2055
    { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG },
2056
    { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG },
2057
    { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2058
    { "bench", TCC_OPTION_bench, 0 },
2059
#ifdef CONFIG_TCC_BACKTRACE
2060
    { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG },
2061
#endif
2062
#ifdef CONFIG_TCC_BCHECK
2063
    { "b", TCC_OPTION_b, 0 },
2064
#endif
2065
    { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2066
    { "c", TCC_OPTION_c, 0 },
2067
    { "C", TCC_OPTION_C, 0 },
2068
    { "dumpversion", TCC_OPTION_dumpversion, 0},
2069
    { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2070
#ifdef TCC_TARGET_ARM
2071
    { "mfloat-abi", TCC_OPTION_float_abi, TCC_OPTION_HAS_ARG },
2072
#endif
2073
    { "static", TCC_OPTION_static, 0 },
2074
    { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2075
    { "shared", TCC_OPTION_shared, 0 },
2076
    { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG },
2077
    { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
2078
    { "pedantic", TCC_OPTION_pedantic, 0},
2079
    { "pthread", TCC_OPTION_pthread, 0},
2080
    { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2081
    { "rdynamic", TCC_OPTION_rdynamic, 0 },
2082
    { "r", TCC_OPTION_r, 0 },
2083
    { "s", TCC_OPTION_s, 0 },
2084
    { "traditional", TCC_OPTION_traditional, 0 },
2085
    { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2086
    { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2087
    { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2088
    { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG },
2089
    { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2090
    { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
2091
    { "iwithprefix", TCC_OPTION_iwithprefix, TCC_OPTION_HAS_ARG },
2092
    { "nostdinc", TCC_OPTION_nostdinc, 0 },
2093
    { "nostdlib", TCC_OPTION_nostdlib, 0 },
2094
    { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
2095
    { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
2096
    { "w", TCC_OPTION_w, 0 },
2097
    { "pipe", TCC_OPTION_pipe, 0},
2098
    { "E", TCC_OPTION_E, 0},
2099
    { "MD", TCC_OPTION_MD, 0},
2100
    { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG },
2101
    { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
6441 siemargl 2102
    { "stack", TCC_OPTION_stack, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP},
6429 siemargl 2103
    { NULL, 0, 0 },
2104
};
2105
 
2106
static void parse_option_D(TCCState *s1, const char *optarg)
2107
{
2108
    char *sym = tcc_strdup(optarg);
2109
    char *value = strchr(sym, '=');
2110
    if (value)
2111
        *value++ = '\0';
2112
    tcc_define_symbol(s1, sym, value);
2113
    tcc_free(sym);
2114
}
2115
 
2116
static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
2117
{
2118
    int len = strlen(filename);
2119
    char *p = tcc_malloc(len + 2);
2120
    if (filetype) {
2121
        *p = filetype;
2122
    }
2123
    else {
2124
        /* use a file extension to detect a filetype */
2125
        const char *ext = tcc_fileextension(filename);
2126
        if (ext[0]) {
2127
            ext++;
2128
            if (!strcmp(ext, "S"))
2129
                *p = TCC_FILETYPE_ASM_PP;
2130
            else
2131
            if (!strcmp(ext, "s"))
2132
                *p = TCC_FILETYPE_ASM;
2133
            else
2134
            if (!PATHCMP(ext, "c") || !PATHCMP(ext, "i"))
2135
                *p = TCC_FILETYPE_C;
2136
            else
2137
                *p = TCC_FILETYPE_BINARY;
2138
        }
2139
        else {
2140
            *p = TCC_FILETYPE_C;
2141
        }
2142
    }
2143
    strcpy(p+1, filename);
2144
    dynarray_add((void ***)&s->files, &s->nb_files, p);
2145
}
2146
 
2147
ST_FUNC int tcc_parse_args1(TCCState *s, int argc, char **argv)
2148
{
2149
    const TCCOption *popt;
2150
    const char *optarg, *r;
2151
    int optind = 0;
2152
    ParseArgsState *pas = s->parse_args_state;
2153
 
6460 siemargl 2154
/*
2155
#ifdef TCC_TARGET_MEOS
2156
// siemargl testing
2157
	s->output_format = TCC_OUTPUT_FORMAT_COFF;
2158
#endif
2159
*/
6429 siemargl 2160
    while (optind < argc) {
2161
 
2162
        r = argv[optind++];
2163
        if (r[0] != '-' || r[1] == '\0') {
2164
            /* handle list files */
2165
            if (r[0] == '@' && r[1]) {
2166
                char buf[sizeof file->filename], *p;
2167
                char **argv = NULL;
2168
                int argc = 0;
2169
                FILE *fp;
2170
 
2171
                fp = fopen(r + 1, "rb");
2172
                if (fp == NULL)
2173
                    tcc_error("list file '%s' not found", r + 1);
2174
                while (fgets(buf, sizeof buf, fp)) {
2175
                    p = trimfront(trimback(buf, strchr(buf, 0)));
2176
                    if (0 == *p || ';' == *p)
2177
                        continue;
2178
                    dynarray_add((void ***)&argv, &argc, tcc_strdup(p));
2179
                }
2180
                fclose(fp);
2181
                tcc_parse_args1(s, argc, argv);
2182
                dynarray_reset(&argv, &argc);
2183
            } else {
2184
                args_parser_add_file(s, r, pas->filetype);
2185
                if (pas->run) {
2186
                    optind--;
2187
                    /* argv[0] will be this file */
2188
                    break;
2189
                }
2190
            }
2191
            continue;
2192
        }
2193
 
2194
        /* find option in table */
2195
        for(popt = tcc_options; ; ++popt) {
2196
            const char *p1 = popt->name;
2197
            const char *r1 = r + 1;
2198
            if (p1 == NULL)
2199
                tcc_error("invalid option -- '%s'", r);
2200
            if (!strstart(p1, &r1))
2201
                continue;
2202
            optarg = r1;
2203
            if (popt->flags & TCC_OPTION_HAS_ARG) {
2204
                if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) {
2205
                    if (optind >= argc)
2206
                        tcc_error("argument to '%s' is missing", r);
2207
                    optarg = argv[optind++];
2208
                }
2209
            } else if (*r1 != '\0')
2210
                continue;
2211
            break;
2212
        }
2213
 
2214
        switch(popt->index) {
2215
        case TCC_OPTION_HELP:
2216
            return 0;
2217
        case TCC_OPTION_I:
2218
            tcc_add_include_path(s, optarg);
2219
            break;
2220
        case TCC_OPTION_D:
2221
            parse_option_D(s, optarg);
2222
            break;
2223
        case TCC_OPTION_U:
2224
            tcc_undefine_symbol(s, optarg);
2225
            break;
2226
        case TCC_OPTION_L:
2227
            tcc_add_library_path(s, optarg);
2228
            break;
2229
        case TCC_OPTION_B:
2230
            /* set tcc utilities path (mainly for tcc development) */
2231
            tcc_set_lib_path(s, optarg);
2232
            break;
2233
        case TCC_OPTION_l:
2234
            args_parser_add_file(s, r, TCC_FILETYPE_BINARY);
2235
            s->nb_libraries++;
2236
            break;
2237
        case TCC_OPTION_pthread:
2238
            parse_option_D(s, "_REENTRANT");
2239
            pas->pthread = 1;
2240
            break;
2241
        case TCC_OPTION_bench:
2242
            s->do_bench = 1;
2243
            break;
2244
#ifdef CONFIG_TCC_BACKTRACE
2245
        case TCC_OPTION_bt:
2246
            tcc_set_num_callers(atoi(optarg));
2247
            break;
2248
#endif
2249
#ifdef CONFIG_TCC_BCHECK
2250
        case TCC_OPTION_b:
2251
            s->do_bounds_check = 1;
2252
            s->do_debug = 1;
2253
            break;
2254
#endif
2255
        case TCC_OPTION_g:
2256
            s->do_debug = 1;
2257
            break;
2258
        case TCC_OPTION_c:
2259
            if (s->output_type)
2260
                tcc_warning("-c: some compiler action already specified (%d)", s->output_type);
2261
            s->output_type = TCC_OUTPUT_OBJ;
2262
            break;
2263
        case TCC_OPTION_C:
2264
            s->option_C = 1;
2265
            break;
2266
        case TCC_OPTION_d:
2267
            if (*optarg == 'D' || *optarg == 'M')
2268
                s->dflag = *optarg;
2269
            else {
2270
                if (s->warn_unsupported)
2271
                    goto unsupported_option;
2272
                tcc_error("invalid option -- '%s'", r);
2273
            }
2274
            break;
2275
#ifdef TCC_TARGET_ARM
2276
        case TCC_OPTION_float_abi:
2277
            /* tcc doesn't support soft float yet */
2278
            if (!strcmp(optarg, "softfp")) {
2279
                s->float_abi = ARM_SOFTFP_FLOAT;
2280
                tcc_undefine_symbol(s, "__ARM_PCS_VFP");
2281
            } else if (!strcmp(optarg, "hard"))
2282
                s->float_abi = ARM_HARD_FLOAT;
2283
            else
2284
                tcc_error("unsupported float abi '%s'", optarg);
2285
            break;
2286
#endif
2287
        case TCC_OPTION_static:
2288
            s->static_link = 1;
2289
            break;
2290
        case TCC_OPTION_std:
2291
    	    /* silently ignore, a current purpose:
2292
    	       allow to use a tcc as a reference compiler for "make test" */
2293
            break;
2294
        case TCC_OPTION_shared:
2295
    	    if (s->output_type)
2296
                tcc_warning("-shared: some compiler action already specified (%d)", s->output_type);
2297
            s->output_type = TCC_OUTPUT_DLL;
2298
            break;
2299
        case TCC_OPTION_soname:
2300
            s->soname = tcc_strdup(optarg);
2301
            break;
2302
        case TCC_OPTION_m:
2303
            s->option_m = tcc_strdup(optarg);
2304
            break;
2305
        case TCC_OPTION_o:
2306
            if (s->outfile) {
2307
                tcc_warning("multiple -o option");
2308
                tcc_free(s->outfile);
2309
            }
2310
            s->outfile = tcc_strdup(optarg);
2311
            break;
2312
        case TCC_OPTION_r:
2313
            /* generate a .o merging several output files */
2314
    	    if (s->output_type)
2315
                tcc_warning("-r: some compiler action already specified (%d)", s->output_type);
2316
            s->option_r = 1;
2317
            s->output_type = TCC_OUTPUT_OBJ;
2318
            break;
2319
        case TCC_OPTION_isystem:
2320
            tcc_add_sysinclude_path(s, optarg);
2321
            break;
2322
        case TCC_OPTION_iwithprefix:
2323
            if (1) {
2324
                char buf[1024];
2325
                int buf_size = sizeof(buf)-1;
2326
                char *p = &buf[0];
2327
 
2328
                char *sysroot = "{B}/";
2329
                int len = strlen(sysroot);
2330
                if (len > buf_size)
2331
                    len = buf_size;
2332
                strncpy(p, sysroot, len);
2333
                p += len;
2334
                buf_size -= len;
2335
 
2336
                len = strlen(optarg);
2337
                if (len > buf_size)
2338
                    len = buf_size;
2339
                strncpy(p, optarg, len+1);
2340
                tcc_add_sysinclude_path(s, buf);
2341
            }
2342
            break;
2343
        case TCC_OPTION_nostdinc:
2344
            s->nostdinc = 1;
2345
            break;
2346
        case TCC_OPTION_nostdlib:
2347
            s->nostdlib = 1;
2348
            break;
2349
        case TCC_OPTION_print_search_dirs:
2350
            s->print_search_dirs = 1;
2351
            break;
2352
        case TCC_OPTION_run:
2353
    	    if (s->output_type)
2354
                tcc_warning("-run: some compiler action already specified (%d)", s->output_type);
2355
            s->output_type = TCC_OUTPUT_MEMORY;
2356
            tcc_set_options(s, optarg);
2357
            pas->run = 1;
2358
            break;
2359
        case TCC_OPTION_v:
2360
            do ++s->verbose; while (*optarg++ == 'v');
2361
            break;
2362
        case TCC_OPTION_f:
2363
            if (tcc_set_flag(s, optarg, 1) < 0 && s->warn_unsupported)
2364
                goto unsupported_option;
2365
            break;
2366
        case TCC_OPTION_W:
2367
            if (tcc_set_warning(s, optarg, 1) < 0 &&
2368
                s->warn_unsupported)
2369
                goto unsupported_option;
2370
            break;
2371
        case TCC_OPTION_w:
2372
            s->warn_none = 1;
2373
            break;
2374
        case TCC_OPTION_rdynamic:
2375
            s->rdynamic = 1;
2376
            break;
2377
        case TCC_OPTION_Wl:
2378
            if (pas->linker_arg.size)
2379
                --pas->linker_arg.size, cstr_ccat(&pas->linker_arg, ',');
2380
            cstr_cat(&pas->linker_arg, optarg, 0);
2381
            break;
2382
        case TCC_OPTION_E:
2383
    	    if (s->output_type)
2384
                tcc_warning("-E: some compiler action already specified (%d)", s->output_type);
2385
            s->output_type = TCC_OUTPUT_PREPROCESS;
2386
            break;
2387
        case TCC_OPTION_P:
2388
            s->Pflag = atoi(optarg) + 1;
2389
            break;
2390
        case TCC_OPTION_MD:
2391
            s->gen_deps = 1;
2392
            break;
2393
        case TCC_OPTION_MF:
2394
            s->deps_outfile = tcc_strdup(optarg);
2395
            break;
2396
        case TCC_OPTION_dumpversion:
2397
            printf ("%s\n", TCC_VERSION);
2398
            exit(0);
2399
        case TCC_OPTION_s:
2400
            s->do_strip = 1;
2401
            break;
2402
        case TCC_OPTION_traditional:
2403
            break;
2404
        case TCC_OPTION_x:
2405
            if (*optarg == 'c')
2406
                pas->filetype = TCC_FILETYPE_C;
2407
            else
2408
            if (*optarg == 'a')
2409
                pas->filetype = TCC_FILETYPE_ASM_PP;
2410
            else
2411
            if (*optarg == 'n')
2412
                pas->filetype = 0;
2413
            else
2414
                tcc_warning("unsupported language '%s'", optarg);
2415
            break;
2416
        case TCC_OPTION_O:
2417
            if (1) {
2418
                int opt = atoi(optarg);
2419
                char *sym = "__OPTIMIZE__";
2420
                if (opt)
2421
                    tcc_define_symbol(s, sym, 0);
2422
                else
2423
                    tcc_undefine_symbol(s, sym);
2424
            }
2425
            break;
2426
        case TCC_OPTION_pedantic:
2427
        case TCC_OPTION_pipe:
2428
            /* ignored */
2429
            break;
6441 siemargl 2430
        case TCC_OPTION_stack:
2431
#ifdef TCC_TARGET_MEOS
2432
            s->pe_stack_size = strtoul(optarg+1, NULL, 10);
2433
#endif
2434
            break;
6429 siemargl 2435
        default:
2436
            if (s->warn_unsupported) {
2437
            unsupported_option:
2438
                tcc_warning("unsupported option '%s'", r);
2439
            }
2440
            break;
2441
        }
2442
    }
2443
    return optind;
2444
}
2445
 
2446
PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv)
2447
{
2448
    ParseArgsState *pas;
2449
    int ret, is_allocated = 0;
2450
 
2451
    if (!s->parse_args_state) {
2452
        s->parse_args_state = tcc_mallocz(sizeof(ParseArgsState));
2453
        cstr_new(&s->parse_args_state->linker_arg);
2454
        is_allocated = 1;
2455
    }
2456
    pas = s->parse_args_state;
2457
 
2458
    ret = tcc_parse_args1(s, argc, argv);
2459
 
2460
    if (s->output_type == 0)
2461
        s->output_type = TCC_OUTPUT_EXE;
2462
 
2463
    if (pas->pthread && s->output_type != TCC_OUTPUT_OBJ)
2464
        tcc_set_options(s, "-lpthread");
2465
 
2466
    if (s->output_type == TCC_OUTPUT_EXE)
2467
        tcc_set_linker(s, (const char *)pas->linker_arg.data);
2468
 
2469
    if (is_allocated) {
2470
        cstr_free(&pas->linker_arg);
2471
        tcc_free(pas);
2472
        s->parse_args_state = NULL;
2473
    }
2474
    return ret;
2475
}
2476
 
2477
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str)
2478
{
2479
    const char *s1;
2480
    char **argv, *arg;
2481
    int argc, len;
2482
    int ret;
2483
 
2484
    argc = 0, argv = NULL;
2485
    for(;;) {
2486
        while (is_space(*str))
2487
            str++;
2488
        if (*str == '\0')
2489
            break;
2490
        s1 = str;
2491
        while (*str != '\0' && !is_space(*str))
2492
            str++;
2493
        len = str - s1;
2494
        arg = tcc_malloc(len + 1);
2495
        pstrncpy(arg, s1, len);
2496
        dynarray_add((void ***)&argv, &argc, arg);
2497
    }
2498
    ret = tcc_parse_args(s, argc, argv);
2499
    dynarray_reset(&argv, &argc);
2500
    return ret;
2501
}
2502
 
2503
PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time)
2504
{
2505
    double tt;
2506
    tt = (double)total_time / 1000000.0;
2507
    if (tt < 0.001)
2508
        tt = 0.001;
2509
    if (total_bytes < 1)
2510
        total_bytes = 1;
6574 siemargl 2511
    fprintf(stdout, "%d idents, %d lines, %d bytes, %0.3f s, %d lines/s, %0.1f MB/s\n",
6429 siemargl 2512
           tok_ident - TOK_IDENT, total_lines, total_bytes,
2513
           tt, (int)(total_lines / tt),
2514
           total_bytes / tt / 1000000.0);
2515
}
2516
 
2517
PUB_FUNC void tcc_set_environment(TCCState *s)
2518
{
2519
    char * path;
2520
 
2521
    path = getenv("C_INCLUDE_PATH");
2522
    if(path != NULL) {
2523
        tcc_add_include_path(s, path);
2524
    }
2525
    path = getenv("CPATH");
2526
    if(path != NULL) {
2527
        tcc_add_include_path(s, path);
2528
    }
2529
    path = getenv("LIBRARY_PATH");
2530
    if(path != NULL) {
2531
        tcc_add_library_path(s, path);
2532
    }
2533
}