History

linker options & tcc_load_ldscript() reworked

cleanup libtcc.c:tcc_set_linker() cleanup tccelf.c:tcc_load_ldscript() Also - tccrun.c, tccelf.c:relocate_syms(): with tcc -run -nostdlib, do resolve but only from explicitly on the command-line given libraries. - tccgen.c: optimize UMOD x % c -> x & (c-1) for c = 2^n - tcc-doc.texi: cleanup - tcc.h, tccpp.c, libtcc.c: add 'size' arg to pstrncpy() Also reorder functions in libtcc.c a bit. 9 files changed, 556 insertions(+), 617 deletions(-)

grischka committed 1 year ago

Commit f10ab131 parent b3381269 files · +556 −617Browse files

Unified · Split

9 files
  1. libtcc.c +418 −465
  2. tcc-doc.texi +12 −10
  3. tcc.c +6 −4
  4. tcc.h +12 −11
  5. tccelf.c +94 −114
  6. tccgen.c +6 −1
  7. tccmacho.c +4 −8
  8. tccpp.c +2 −2
  9. tccrun.c +2 −2
libtcc.c+418−465
@@ -175,9 +175,11 @@ ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s) · 174 unmodified lines
175175 return buf;
176176 }
177177
178−ST_FUNC char *pstrncpy(char *out, const char *in, size_t num)
178+ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num)
179179 {
180− memcpy(out, in, num);
180+ if (num >= buf_size)
181+ num = buf_size - 1;
182+ memcpy(out, s, num);
181183 out[num] = '\0';
182184 return out;
183185 }
@@ -206,11 +208,26 @@ ST_FUNC char *tcc_load_text(int fd) · 22 unmodified lines
206208 {
207209 int len = lseek(fd, 0, SEEK_END);
208210 char *buf = load_data(fd, 0, len + 1);
209− if (buf)
210− buf[len] = 0;
211+ buf[len] = 0;
211212 return buf;
212213 }
213214
215+/* replace *pp by copy of 'str' or NULL */
216+static void tcc_set_str(char **pp, const char *str)
217+{
218+ tcc_free(*pp);
219+ *pp = str ? tcc_strdup(str) : NULL;
220+}
221+
222+/* set/append 'str' to *pp (separated by 'sep' unless 0) */
223+static void tcc_concat_str(char **pp, const char *str, int sep)
224+{
225+ int l = *pp ? strlen(*pp) + !!sep : 0;
226+ *pp = tcc_realloc(*pp, l + strlen(str) + 1);
227+ if (l && sep) ((*pp)[l - 1] = sep);
228+ strcpy(*pp + l, str);
229+}
230+
214231 /********************************************************/
215232 /* memory management */
216233
@@ -519,6 +536,41 @@ ST_FUNC void dynarray_reset(void *pp, int *n) · 302 unmodified lines
519536 *(void**)pp = NULL;
520537 }
521538
539+static void dynarray_split(char ***argv, int *argc, const char *p, int sep)
540+{
541+ int qot, c;
542+ CString str;
543+ for(;;) {
544+ while (c = (unsigned char)*p, c <= ' ' && c != '\0')
545+ ++p;
546+ if (c == '\0')
547+ break;
548+ cstr_new(&str);
549+ qot = 0;
550+ do {
551+ ++p;
552+ if (sep) { /* e.g. to split -Wl,-opt,arg */
553+ if (c == sep)
554+ break;
555+ } else {
556+ /* e.g. for tcc_set_options() or "tcc @listfile" */
557+ if (c == '\\' && (*p == '"' || *p == '\\')) {
558+ c = *p++;
559+ } else if (c == '"') {
560+ qot ^= 1;
561+ continue;
562+ } else if (c <= ' ' && !qot) {
563+ break;
564+ }
565+ }
566+ cstr_ccat(&str, c);
567+ } while (c = (unsigned char)*p, c != '\0');
568+ cstr_ccat(&str, '\0');
569+ //printf("<%s>\n", str.data);
570+ dynarray_add(argv, argc, str.data);
571+ }
572+}
573+
522574 static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in)
523575 {
524576 const char *p;
@@ -885,9 +937,9 @@ LIBTCCAPI void tcc_delete(TCCState *s1) · 360 unmodified lines
885937 dynarray_reset(&s1->target_deps, &s1->nb_target_deps);
886938 dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs);
887939 dynarray_reset(&s1->argv, &s1->argc);
940+ dynarray_reset(&s1->link_argv, &s1->link_argc);
888941 cstr_free(&s1->cmdline_defs);
889942 cstr_free(&s1->cmdline_incl);
890− cstr_free(&s1->linker_arg);
891943 tcc_free(s1->dState);
892944 #ifdef TCC_IS_NATIVE
893945 /* free runtime memory */
@@ -962,6 +1014,17 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) · 68 unmodified lines
9621014 return 0;
9631015 }
9641016
1017+LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
1018+{
1019+ tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
1020+ return 0;
1021+}
1022+
1023+LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
1024+{
1025+ tcc_set_str(&s->tcc_lib_path, path);
1026+}
1027+
9651028 /* add/update a 'DLLReference', Just find if level == -1 */
9661029 ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level)
9671030 {
@@ -988,6 +1051,109 @@ ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int leve · 20 unmodified lines
9881051 return ref;
9891052 }
9901053
1054+static int tcc_add_binary(TCCState *s1, int flags, const char *filename, int fd)
1055+{
1056+ ElfW(Ehdr) ehdr;
1057+ int obj_type;
1058+ const char *saved_filename = s1->current_filename;
1059+ int ret = 0;
1060+
1061+ s1->current_filename = filename;
1062+ obj_type = tcc_object_type(fd, &ehdr);
1063+ lseek(fd, 0, SEEK_SET);
1064+
1065+ switch (obj_type) {
1066+
1067+ case AFF_BINTYPE_REL:
1068+ ret = tcc_load_object_file(s1, fd, 0);
1069+ break;
1070+
1071+ case AFF_BINTYPE_AR:
1072+ ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
1073+ break;
1074+
1075+#if defined TCC_TARGET_UNIX
1076+ case AFF_BINTYPE_DYN:
1077+ if (s1->output_type == TCC_OUTPUT_MEMORY) {
1078+#ifdef TCC_IS_NATIVE
1079+ void* dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
1080+ if (dl)
1081+ tcc_add_dllref(s1, filename, 0)->handle = dl;
1082+ else
1083+ ret = FILE_NOT_RECOGNIZED;
1084+#endif
1085+ } else
1086+ ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1087+ break;
1088+
1089+ default:
1090+ /* as GNU ld, consider it is an ld script if not recognized */
1091+ ret = tcc_load_ldscript(s1, fd);
1092+ break;
1093+
1094+#elif defined TCC_TARGET_MACHO
1095+ case AFF_BINTYPE_DYN:
1096+ case_dyn_or_tbd:
1097+ if (s1->output_type == TCC_OUTPUT_MEMORY) {
1098+#ifdef TCC_IS_NATIVE
1099+ void* dl;
1100+ const char* soname = filename;
1101+ char *tmp = 0;
1102+ if (obj_type != AFF_BINTYPE_DYN) {
1103+ tmp = macho_tbd_soname(fd);
1104+ if (tmp)
1105+ soname = tmp;
1106+ }
1107+ dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY);
1108+ if (dl)
1109+ tcc_add_dllref(s1, soname, 0)->handle = dl;
1110+ else
1111+ ret = FILE_NOT_RECOGNIZED;
1112+ tcc_free(tmp);
1113+#endif
1114+ } else if (obj_type == AFF_BINTYPE_DYN) {
1115+ ret = macho_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1116+ } else {
1117+ ret = macho_load_tbd(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1118+ }
1119+ if (ret)
1120+ ret = FILE_NOT_RECOGNIZED;
1121+ break;
1122+
1123+ default:
1124+ {
1125+ const char *ext = tcc_fileextension(filename);
1126+ if (!strcmp(ext, ".tbd"))
1127+ goto case_dyn_or_tbd;
1128+ if (!strcmp(ext, ".dylib")) {
1129+ obj_type = AFF_BINTYPE_DYN;
1130+ goto case_dyn_or_tbd;
1131+ }
1132+ ret = FILE_NOT_RECOGNIZED;
1133+ break;
1134+ }
1135+
1136+#elif defined TCC_TARGET_PE
1137+ default:
1138+ if (pe_load_file(s1, fd, filename))
1139+ ret = FILE_NOT_RECOGNIZED;
1140+ break;
1141+#endif
1142+
1143+#ifdef TCC_TARGET_COFF
1144+ case AFF_BINTYPE_C67:
1145+ ret = tcc_load_coff(s1, fd);
1146+ break;
1147+#endif
1148+ }
1149+
1150+ close(fd);
1151+ s1->current_filename = saved_filename;
1152+ if (ret == FILE_NOT_RECOGNIZED)
1153+ return tcc_error_noabort("%s: unrecognized file type", filename);
1154+ return ret;
1155+}
1156+
9911157 /* OpenBSD: choose latest from libxxx.so.x.y versions */
9921158 #if defined TARGETOS_OpenBSD && !defined _WIN32
9931159 #include <glob.h>
@@ -1013,11 +1179,34 @@ static int tcc_glob_so(TCCState *s1, const char *pattern, char *buf, int size) · 19 unmodified lines
10131179 }
10141180 #endif
10151181
1016−static int guess_filetype(const char *filename);
1182+static int guess_filetype(const char *filename)
1183+{
1184+ int filetype = 0;
1185+ if (1) {
1186+ /* use a file extension to detect a filetype */
1187+ const char *ext = tcc_fileextension(filename);
1188+ if (ext[0]) {
1189+ ext++;
1190+ if (!strcmp(ext, "S"))
1191+ filetype = AFF_TYPE_ASMPP;
1192+ else if (!strcmp(ext, "s"))
1193+ filetype = AFF_TYPE_ASM;
1194+ else if (!PATHCMP(ext, "c")
1195+ || !PATHCMP(ext, "h")
1196+ || !PATHCMP(ext, "i"))
1197+ filetype = AFF_TYPE_C;
1198+ else
1199+ filetype |= AFF_TYPE_BIN;
1200+ } else {
1201+ filetype = AFF_TYPE_C;
1202+ }
1203+ }
1204+ return filetype;
1205+}
10171206
10181207 ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
10191208 {
1020− int fd, ret = -1;
1209+ int fd;
10211210
10221211 #if defined TARGETOS_OpenBSD && !defined _WIN32
10231212 char buf[1024];
@@ -1041,125 +1230,11 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 17 unmodified lines
10411230 return FILE_NOT_FOUND;
10421231 }
10431232
1044− s1->current_filename = filename;
1045− if (flags & AFF_TYPE_BIN) {
1046− ElfW(Ehdr) ehdr;
1047− int obj_type;
1048−
1049− obj_type = tcc_object_type(fd, &ehdr);
1050− lseek(fd, 0, SEEK_SET);
1051−
1052− switch (obj_type) {
1053−
1054− case AFF_BINTYPE_REL:
1055− ret = tcc_load_object_file(s1, fd, 0);
1056− break;
1057−
1058− case AFF_BINTYPE_AR:
1059− ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
1060− break;
1061−
1062−#ifdef TCC_TARGET_PE
1063− default:
1064− ret = pe_load_file(s1, fd, filename);
1065− goto check_success;
1066−
1067−#elif defined TCC_TARGET_MACHO
1068− case AFF_BINTYPE_DYN:
1069− case_dyn_or_tbd:
1070− if (s1->output_type == TCC_OUTPUT_MEMORY) {
1071−#ifdef TCC_IS_NATIVE
1072− void* dl;
1073− const char* soname = filename;
1074− if (obj_type != AFF_BINTYPE_DYN)
1075− soname = macho_tbd_soname(filename);
1076− dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY);
1077− if (dl)
1078− tcc_add_dllref(s1, soname, 0)->handle = dl, ret = 0;
1079− if (filename != soname)
1080− tcc_free((void *)soname);
1081−#endif
1082− } else if (obj_type == AFF_BINTYPE_DYN) {
1083− ret = macho_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1084− } else {
1085− ret = macho_load_tbd(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1086− }
1087− goto check_success;
1088− default:
1089− {
1090− const char *ext = tcc_fileextension(filename);
1091− if (!strcmp(ext, ".tbd"))
1092− goto case_dyn_or_tbd;
1093− if (!strcmp(ext, ".dylib")) {
1094− obj_type = AFF_BINTYPE_DYN;
1095− goto case_dyn_or_tbd;
1096− }
1097− goto check_success;
1098− }
1099−
1100−#else /* unix */
1101− case AFF_BINTYPE_DYN:
1102− if (s1->output_type == TCC_OUTPUT_MEMORY) {
1103−#ifdef TCC_IS_NATIVE
1104− void* dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
1105− if (dl)
1106− tcc_add_dllref(s1, filename, 0)->handle = dl, ret = 0;
1107−#endif
1108− } else
1109− ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0);
1110− break;
1111−
1112− default:
1113− /* as GNU ld, consider it is an ld script if not recognized */
1114− ret = tcc_load_ldscript(s1, fd);
1115− goto check_success;
1233+ if (flags & AFF_TYPE_BIN)
1234+ return tcc_add_binary(s1, flags, filename, fd);
11161235
1117−#endif /* pe / macos / unix */
1118−
1119−check_success:
1120− if (ret < 0)
1121− tcc_error_noabort("%s: unrecognized file type", filename);
1122− break;
1123−
1124−#ifdef TCC_TARGET_COFF
1125− case AFF_BINTYPE_C67:
1126− ret = tcc_load_coff(s1, fd);
1127− break;
1128−#endif
1129− }
1130− close(fd);
1131− } else {
1132− /* update target deps */
1133− dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
1134− ret = tcc_compile(s1, flags, filename, fd);
1135− }
1136− s1->current_filename = NULL;
1137− return ret;
1138−}
1139−
1140−static int guess_filetype(const char *filename)
1141−{
1142− int filetype = 0;
1143− if (1) {
1144− /* use a file extension to detect a filetype */
1145− const char *ext = tcc_fileextension(filename);
1146− if (ext[0]) {
1147− ext++;
1148− if (!strcmp(ext, "S"))
1149− filetype = AFF_TYPE_ASMPP;
1150− else if (!strcmp(ext, "s"))
1151− filetype = AFF_TYPE_ASM;
1152− else if (!PATHCMP(ext, "c")
1153− || !PATHCMP(ext, "h")
1154− || !PATHCMP(ext, "i"))
1155− filetype = AFF_TYPE_C;
1156− else
1157− filetype |= AFF_TYPE_BIN;
1158− } else {
1159− filetype = AFF_TYPE_C;
1160− }
1161− }
1162− return filetype;
1236+ dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
1237+ return tcc_compile(s1, flags, filename, fd);
11631238 }
11641239
11651240 LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
@@ -1167,12 +1242,6 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) · 1 unmodified line
11671242 return tcc_add_file_internal(s, filename, s->filetype | AFF_PRINT_ERROR);
11681243 }
11691244
1170−LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname)
1171−{
1172− tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname);
1173− return 0;
1174−}
1175−
11761245 static int tcc_add_library_internal(TCCState *s1, const char *fmt,
11771246 const char *filename, int flags, char **paths, int nb_paths)
11781247 {
@@ -1186,7 +1255,8 @@ static int tcc_add_library_internal(TCCState *s1, const char *fmt, · 7 unmodified lines
11861255 return ret;
11871256 }
11881257 if (flags & AFF_PRINT_ERROR)
1189− tcc_error_noabort("library '%s' not found", filename);
1258+ tcc_error_noabort("%s '%s' not found",
1259+ flags & AFF_TYPE_LIB ? "library" : "file", filename);
11901260 return FILE_NOT_FOUND;
11911261 }
11921262
@@ -1206,7 +1276,7 @@ ST_FUNC int tcc_add_support(TCCState *s1, const char *filename) · 13 unmodified lines
12061276 return tcc_add_dll(s1, filename, AFF_PRINT_ERROR);
12071277 }
12081278
1209−#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO
1279+#ifdef TCC_TARGET_UNIX
12101280 ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename)
12111281 {
12121282 return tcc_add_library_internal(s1, "%s/%s",
@@ -1230,12 +1300,12 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) · 17 unmodified lines
12301300 "%s/lib%s.a",
12311301 NULL
12321302 };
1303+ int flags = AFF_TYPE_LIB | (s->filetype & AFF_WHOLE_ARCHIVE);
12331304 /* if libraryname begins with a colon, it means search lib paths for
12341305 exactly the following file, without lib prefix or anything */
12351306 if (*libraryname == ':') {
12361307 libraryname++;
12371308 } else {
1238− int flags = s->filetype & AFF_WHOLE_ARCHIVE;
12391309 const char * const *pp = libs;
12401310 if (s->static_link)
12411311 pp += sizeof(libs) / sizeof(*libs) - 2; /* only "%s/lib%s.a" */
@@ -1247,7 +1317,8 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) · 5 unmodified lines
12471317 ++pp;
12481318 }
12491319 }
1250− return tcc_add_dll(s, libraryname, AFF_PRINT_ERROR);
1320+ /* fallback to try file without pre- or sufffix */
1321+ return tcc_add_dll(s, libraryname, flags | AFF_PRINT_ERROR);
12511322 }
12521323
12531324 /* handle #pragma comment(lib,) */
@@ -1258,30 +1329,6 @@ ST_FUNC void tcc_add_pragma_libs(TCCState *s1) · 4 unmodified lines
12581329 tcc_add_library(s1, s1->pragma_libs[i]);
12591330 }
12601331
1261−LIBTCCAPI int tcc_add_symbol(TCCState *s1, const char *name, const void *val)
1262−{
1263−#ifdef TCC_TARGET_PE
1264− /* On x86_64 'val' might not be reachable with a 32bit offset.
1265− So it is handled here as if it were in a DLL. */
1266− pe_putimport(s1, 0, name, (uintptr_t)val);
1267−#else
1268− char buf[256];
1269− if (s1->leading_underscore) {
1270− buf[0] = '_';
1271− pstrcpy(buf + 1, sizeof(buf) - 1, name);
1272− name = buf;
1273− }
1274− set_global_sym(s1, name, NULL, (addr_t)(uintptr_t)val); /* NULL: SHN_ABS */
1275−#endif
1276− return 0;
1277−}
1278−
1279−LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
1280−{
1281− tcc_free(s->tcc_lib_path);
1282− s->tcc_lib_path = tcc_strdup(path);
1283−}
1284−
12851332 /********************************************************/
12861333 /* options parser */
12871334
@@ -1300,224 +1347,177 @@ static int strstart(const char *val, const char **str) · 12 unmodified lines
13001347 return 1;
13011348 }
13021349
1303−/* Like strstart, but automatically takes into account that ld options can
1304− *
1305− * - start with double or single dash (e.g. '--soname' or '-soname')
1306− * - arguments can be given as separate or after '=' (e.g. '-Wl,-soname,x.so'
1307− * or '-Wl,-soname=x.so')
1308− *
1309− * you provide `val` always in 'option[=]' form (no leading -)
1310− */
1311−static int link_option(const char *str, const char *val, const char **ptr)
1350+struct lopt {
1351+ TCCState *s;
1352+ const char *opt, *arg;
1353+ int match;
1354+};
1355+
1356+/* match linker option */
1357+static int link_option(struct lopt *o, const char *q)
13121358 {
1313− const char *p, *q;
1314− int ret;
1359+ const char *p = o->opt;
1360+ int c;
13151361
13161362 /* there should be 1 or 2 dashes */
1317− if (*str++ != '-')
1363+ if (*p++ != '-')
13181364 return 0;
1319− if (*str == '-')
1320− str++;
1321−
1322− /* then str & val should match (potentially up to '=') */
1323− p = str;
1324− q = val;
1325−
1326− ret = 1;
1327− if (q[0] == '?') {
1328− ++q;
1329− if (strstart("no-", &p))
1330− ret = -1;
1331− }
1332−
1333− while (*q != '\0' && *q != '=') {
1334− if (*p != *q)
1335− return 0;
1365+ if (*p == '-')
13361366 p++;
1337− q++;
1367+ while ((c = *q) == *p) {
1368+ if (c == '\0')
1369+ goto succ; /* -Wl,-opt */
1370+ ++p;
1371+ if (c == '=')
1372+ goto succ; /* -Wl,-opt=arg */
1373+ ++q;
13381374 }
1339−
1340− /* '=' near eos means ',' or '=' is ok */
1341− if (*q == '=') {
1342− if (*p == 0)
1343− *ptr = p;
1344− if (*p != ',' && *p != '=')
1345− return 0;
1346− p++;
1347− } else if (*p && *p != ',') {
1348− return 0;
1375+ if (c == '=' || c == ':') {
1376+ if (*p == '\0') {
1377+ if (o->s->link_optind + 1 < o->s->link_argc) {
1378+ p = o->s->link_argv[++o->s->link_optind];
1379+ goto succ; /* -Wl,-opt,arg */
1380+ }
1381+ o->match = 1; /* -Wl,-opt -Wl,arg */
1382+ } else if (c == ':')
1383+ goto succ; /* -Wl,-Iarg */
13491384 }
1350− *ptr = p;
1351− return ret;
1352−}
1353−
1354−static int link_arg(const char *opt, const char *str)
1355−{
1356− int l = strlen(opt);
1357− return 0 == strncmp(opt, str, l) && (str[l] == '\0' || str[l] == ',');
1385+ return 0;
1386+succ:
1387+ o->arg = p;
1388+ //printf("set %s '%s'\n", o->opt, o->arg);
1389+ return 1;
13581390 }
13591391
1360−static const char *skip_linker_arg(const char **str)
1361−{
1362− const char *s1 = *str;
1363− const char *s2 = strchr(s1, ',');
1364− *str = s2 ? s2++ : (s2 = s1 + strlen(s1));
1365− return s2;
1366−}
1367−
1368−static void copy_linker_arg(char **pp, const char *s, int sep)
1369−{
1370− const char *q = s;
1371− char *p = *pp;
1372− int l = 0;
1373− if (p && sep)
1374− p[l = strlen(p)] = sep, ++l;
1375− skip_linker_arg(&q);
1376− pstrncpy(l + (*pp = tcc_realloc(p, q - s + l + 1)), s, q - s);
1377−}
1378−
1379−static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
1380−{
1381− struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
1382− f->type = filetype;
1383− strcpy(f->name, filename);
1384− dynarray_add(&s->files, &s->nb_files, f);
1385−}
1392+static void args_parser_add_file(TCCState *s, const char* filename, int filetype);
13861393
13871394 /* set linker options */
1388−static int tcc_set_linker(TCCState *s, const char *option)
1395+static int tcc_set_linker(TCCState *s, const char *optarg)
13891396 {
13901397 TCCState *s1 = s;
1391− while (*option) {
13921398
1393− const char *p = NULL;
1399+ dynarray_split(&s1->link_argv, &s1->link_argc, optarg, ',');
1400+
1401+ while (s->link_optind < s->link_argc) {
13941402 char *end = NULL;
13951403 int ignoring = 0;
1396− int ret;
1404+ struct lopt o = {0};
1405+ o.s = s;
1406+ o.opt = s->link_argv[s->link_optind];
13971407
1398− if (link_option(option, "Bsymbolic", &p)) {
1408+ if (link_option(&o, "Bsymbolic")) {
13991409 s->symbolic = 1;
1400− } else if (link_option(option, "nostdlib", &p)) {
1410+ } else if (link_option(&o, "nostdlib")) {
14011411 s->nostdlib_paths = 1;
1402− } else if (link_option(option, "e=", &p)
1403− || link_option(option, "entry=", &p)) {
1404− copy_linker_arg(&s->elf_entryname, p, 0);
1405− } else if (link_option(option, "fini=", &p)) {
1406− copy_linker_arg(&s->fini_symbol, p, 0);
1407− ignoring = 1;
1408− } else if (link_option(option, "image-base=", &p)
1409− || link_option(option, "Ttext=", &p)) {
1410− s->text_addr = strtoull(p, &end, 16);
1412+ } else if (link_option(&o, "e=") || link_option(&o, "entry=")) {
1413+ tcc_set_str(&s->elf_entryname, o.arg);
1414+ } else if (link_option(&o, "image-base=") || link_option(&o, "Ttext=")) {
1415+ s->text_addr = strtoull(o.arg, &end, 16);
14111416 s->has_text_addr = 1;
1412− } else if (link_option(option, "init=", &p)) {
1413− copy_linker_arg(&s->init_symbol, p, 0);
1417+ } else if (link_option(&o, "init=")) {
1418+ tcc_set_str(&s->init_symbol, o.arg);
1419+ ignoring = 1;
1420+ } else if (link_option(&o, "fini=")) {
1421+ tcc_set_str(&s->fini_symbol, o.arg);
14141422 ignoring = 1;
1415− } else if (link_option(option, "Map=", &p)) {
1416− copy_linker_arg(&s->mapfile, p, 0);
1423+ } else if (link_option(&o, "Map=")) {
1424+ tcc_set_str(&s->mapfile, o.arg);
14171425 ignoring = 1;
1418− } else if (link_option(option, "oformat=", &p)) {
1419−#if defined(TCC_TARGET_PE)
1420− if (strstart("pe-", &p)) {
1426+ } else if (link_option(&o, "oformat=")) {
1427+#if defined TCC_TARGET_PE
1428+ if (0 == strncmp("pe-", o.arg, 3))
14211429 #elif PTR_SIZE == 8
1422− if (strstart("elf64-", &p)) {
1430+ if (0 == strncmp("elf64-", o.arg, 6))
14231431 #else
1424− if (strstart("elf32-", &p)) {
1432+ if (0 == strncmp("elf32-", o.arg, 6))
14251433 #endif
14261434 s->output_format = TCC_OUTPUT_FORMAT_ELF;
1427− } else if (link_arg("binary", p)) {
1435+ else if (0==strcmp("binary", o.arg))
14281436 s->output_format = TCC_OUTPUT_FORMAT_BINARY;
1429−#ifdef TCC_TARGET_COFF
1430− } else if (link_arg("coff", p)) {
1437+#if defined TCC_TARGET_COFF
1438+ else if (0==strcmp("coff", o.arg))
14311439 s->output_format = TCC_OUTPUT_FORMAT_COFF;
14321440 #endif
1433− } else
1441+ else
14341442 goto err;
1435−
1436− } else if (link_option(option, "as-needed", &p)) {
1437− ignoring = 1;
1438− } else if (link_option(option, "O", &p)) {
1439− ignoring = 1;
1440− } else if (link_option(option, "export-all-symbols", &p)) {
1441− s->rdynamic = 1;
1442− } else if (link_option(option, "export-dynamic", &p)) {
1443+ } else if (link_option(&o, "export-all-symbols")
1444+ || link_option(&o, "export-dynamic")) {
14431445 s->rdynamic = 1;
1444− } else if (link_option(option, "rpath=", &p)) {
1445− copy_linker_arg(&s->rpath, p, ':');
1446− } else if (link_option(option, "dynamic-linker=", &p)
1447− || link_option(option, "I=", &p)) {
1448− copy_linker_arg(&s->elfint, p, 0);
1449− } else if (strncmp("-I/", option, 3) == 0
1450− || strncmp("-I.", option, 3) == 0) {
1451− p = option;
1452− copy_linker_arg(&s->elfint, option + 2, 0);
1453− } else if (link_option(option, "enable-new-dtags", &p)) {
1446+ } else if (link_option(&o, "rpath=")) {
1447+ tcc_concat_str(&s->rpath, o.arg, ':');
1448+ } else if (link_option(&o, "dynamic-linker=") || link_option(&o, "I:")) {
1449+ tcc_set_str(&s->elfint, o.arg);
1450+ } else if (link_option(&o, "enable-new-dtags")) {
14541451 s->enable_new_dtags = 1;
1455− } else if (link_option(option, "section-alignment=", &p)) {
1456− s->section_align = strtoul(p, &end, 16);
1457− } else if (link_option(option, "soname=", &p)) {
1458− copy_linker_arg(&s->soname, p, 0);
1459− } else if (link_option(option, "install_name=", &p)) {
1460− copy_linker_arg(&s->soname, p, 0);
1452+ } else if (link_option(&o, "section-alignment=")) {
1453+ s->section_align = strtoul(o.arg, &end, 16);
1454+ } else if (link_option(&o, "soname=") || link_option(&o, "install_name=")) {
1455+ tcc_set_str(&s->soname, o.arg);
1456+ } else if (link_option(&o, "whole-archive")) {
1457+ s->filetype |= AFF_WHOLE_ARCHIVE;
1458+ } else if (link_option(&o, "no-whole-archive")) {
1459+ s->filetype &= ~AFF_WHOLE_ARCHIVE;
14611460 #ifdef TCC_TARGET_PE
1462− } else if (link_option(option, "large-address-aware", &p)) {
1461+ } else if (link_option(&o, "large-address-aware")) {
14631462 s->pe_characteristics |= 0x20;
1464− } else if (link_option(option, "file-alignment=", &p)) {
1465− s->pe_file_align = strtoul(p, &end, 16);
1466− } else if (link_option(option, "stack=", &p)) {
1467− s->pe_stack_size = strtoul(p, &end, 10);
1468− } else if (link_option(option, "subsystem=", &p)) {
1463+ } else if (link_option(&o, "file-alignment=")) {
1464+ s->pe_file_align = strtoul(o.arg, &end, 16);
1465+ } else if (link_option(&o, "stack=")) {
1466+ s->pe_stack_size = strtoul(o.arg, &end, 10);
1467+ } else if (link_option(&o, "subsystem=")) {
14691468 #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
1470− if (link_arg("native", p)) {
1469+ if (0==strcmp("native", o.arg)) {
14711470 s->pe_subsystem = 1;
1472− } else if (link_arg("console", p)) {
1471+ } else if (0==strcmp("console", o.arg)) {
14731472 s->pe_subsystem = 3;
1474− } else if (link_arg("gui", p) || link_arg("windows", p)) {
1473+ } else if (0==strcmp("gui", o.arg) || 0==strcmp("windows", o.arg)) {
14751474 s->pe_subsystem = 2;
1476− } else if (link_arg("posix", p)) {
1475+ } else if (0==strcmp("posix", o.arg)) {
14771476 s->pe_subsystem = 7;
1478− } else if (link_arg("efiapp", p)) {
1477+ } else if (0==strcmp("efiapp", o.arg)) {
14791478 s->pe_subsystem = 10;
1480− } else if (link_arg("efiboot", p)) {
1479+ } else if (0==strcmp("efiboot", o.arg)) {
14811480 s->pe_subsystem = 11;
1482− } else if (link_arg("efiruntime", p)) {
1481+ } else if (0==strcmp("efiruntime", o.arg)) {
14831482 s->pe_subsystem = 12;
1484− } else if (link_arg("efirom", p)) {
1483+ } else if (0==strcmp("efirom", o.arg)) {
14851484 s->pe_subsystem = 13;
14861485 #elif defined(TCC_TARGET_ARM)
1487− if (link_arg("wince", p)) {
1486+ if (0==strcmp("wince", o.arg)) {
14881487 s->pe_subsystem = 9;
14891488 #endif
14901489 } else
14911490 goto err;
1492−#endif
1491+#endif /* PE */
14931492 #ifdef TCC_TARGET_MACHO
1494− } else if (link_option(option, "all_load", &p)) {
1495− s->filetype |= AFF_WHOLE_ARCHIVE;
1496− } else if (link_option(option, "force_load", &p)) {
1493+ } else if (link_option(&o, "all_load")) {
14971494 s->filetype |= AFF_WHOLE_ARCHIVE;
1498− args_parser_add_file(s, p, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
1499− s->nb_libraries++;
1500− } else if (link_option(option, "single_module", &p)) {
1495+ } else if (link_option(&o, "force_load=")) {
1496+ args_parser_add_file(s, o.arg, AFF_TYPE_LIB | AFF_WHOLE_ARCHIVE);
1497+ } else if (link_option(&o, "single_module")) {
15011498 ignoring = 1;
15021499 #endif
1503− } else if (ret = link_option(option, "?whole-archive", &p), ret) {
1504− if (ret > 0)
1505− s->filetype |= AFF_WHOLE_ARCHIVE;
1506− else
1507− s->filetype &= ~AFF_WHOLE_ARCHIVE;
1508− } else if (link_option(option, "z=", &p)) {
1500+ } else if (link_option(&o, "as-needed")) {
15091501 ignoring = 1;
1510− } else if (p) {
1511− return 0;
1502+ } else if (link_option(&o, "O")) {
1503+ ignoring = 1;
1504+ } else if (link_option(&o, "z=")) {
1505+ ignoring = 1;
1506+ } else if (link_option(&o, "L:")) {
1507+ tcc_add_library_path(s, o.arg);
1508+ } else if (link_option(&o, "l:")) {
1509+ args_parser_add_file(s, o.arg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
1510+ } else if (o.match) {
1511+ return 0; /* expecting argument with next '-Wl,' */
15121512 } else {
15131513 err:
1514− return tcc_error_noabort("unsupported linker option '%s'", option);
1514+ return tcc_error_noabort("unsupported linker option '%s'", o.opt);
15151515 }
15161516 if (ignoring)
1517− tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option);
1518− option = skip_linker_arg(&p);
1517+ tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", o.opt);
1518+ ++s->link_optind;
15191519 }
1520− return 1;
1520+ return 0;
15211521 }
15221522
15231523 typedef struct TCCOption {
@@ -1541,7 +1541,6 @@ enum { · 17 unmodified lines
15411541 TCC_OPTION_bench,
15421542 TCC_OPTION_bt,
15431543 TCC_OPTION_b,
1544− TCC_OPTION_ba,
15451544 TCC_OPTION_g,
15461545 TCC_OPTION_c,
15471546 TCC_OPTION_dumpmachine,
@@ -1580,6 +1579,7 @@ enum { · 32 unmodified lines
15801579 TCC_OPTION_x,
15811580 TCC_OPTION_ar,
15821581 TCC_OPTION_impdef,
1582+ /* macho */
15831583 TCC_OPTION_dynamiclib,
15841584 TCC_OPTION_flat_namespace,
15851585 TCC_OPTION_two_levelnamespace,
@@ -1617,11 +1617,13 @@ static const TCCOption tcc_options[] = { · 31 unmodified lines
16171617 #ifdef TCC_TARGET_MACHO
16181618 { "compatibility_version", TCC_OPTION_compatibility_version, TCC_OPTION_HAS_ARG },
16191619 { "current_version", TCC_OPTION_current_version, TCC_OPTION_HAS_ARG },
1620−#endif
1621− { "c", TCC_OPTION_c, 0 },
1622−#ifdef TCC_TARGET_MACHO
16231620 { "dynamiclib", TCC_OPTION_dynamiclib, 0 },
1621+ { "flat_namespace", TCC_OPTION_flat_namespace, 0 },
1622+ { "install_name", TCC_OPTION_install_name, TCC_OPTION_HAS_ARG },
1623+ { "two_levelnamespace", TCC_OPTION_two_levelnamespace, 0 },
1624+ { "undefined", TCC_OPTION_undefined, TCC_OPTION_HAS_ARG },
16241625 #endif
1626+ { "c", TCC_OPTION_c, 0 },
16251627 { "dumpmachine", TCC_OPTION_dumpmachine, 0},
16261628 { "dumpversion", TCC_OPTION_dumpversion, 0},
16271629 { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
@@ -1642,9 +1644,6 @@ static const TCCOption tcc_options[] = { · 14 unmodified lines
16421644 { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG },
16431645 #endif
16441646 { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
1645−#ifdef TCC_TARGET_MACHO
1646− { "flat_namespace", TCC_OPTION_flat_namespace, 0 },
1647−#endif
16481647 { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
16491648 { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG },
16501649 { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG },
@@ -1660,14 +1659,10 @@ static const TCCOption tcc_options[] = { · 9 unmodified lines
16601659 { "MMD", TCC_OPTION_MMD, 0},
16611660 { "MP", TCC_OPTION_MP, 0},
16621661 { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG },
1662+ /* tcctools */
16631663 { "ar", TCC_OPTION_ar, 0},
16641664 #ifdef TCC_TARGET_PE
16651665 { "impdef", TCC_OPTION_impdef, 0},
1666−#endif
1667−#ifdef TCC_TARGET_MACHO
1668− { "install_name", TCC_OPTION_install_name, TCC_OPTION_HAS_ARG },
1669− { "two_levelnamespace", TCC_OPTION_two_levelnamespace, 0 },
1670− { "undefined", TCC_OPTION_undefined, TCC_OPTION_HAS_ARG },
16711666 #endif
16721667 /* ignored (silently, except after -Wunsupported) */
16731668 { "arch", 0, TCC_OPTION_HAS_ARG},
@@ -1788,65 +1783,6 @@ static const char dumpmachine_str[] = · 114 unmodified lines
17881783 #endif
17891784 ;
17901785
1791−static int args_parser_make_argv(const char *r, int *argc, char ***argv)
1792−{
1793− int ret = 0, q, c;
1794− CString str;
1795− for(;;) {
1796− while (c = (unsigned char)*r, c && c <= ' ')
1797− ++r;
1798− if (c == 0)
1799− break;
1800− q = 0;
1801− cstr_new(&str);
1802− while (c = (unsigned char)*r, c) {
1803− ++r;
1804− if (c == '\\' && (*r == '"' || *r == '\\')) {
1805− c = *r++;
1806− } else if (c == '"') {
1807− q = !q;
1808− continue;
1809− } else if (q == 0 && c <= ' ') {
1810− break;
1811− }
1812− cstr_ccat(&str, c);
1813− }
1814− cstr_ccat(&str, 0);
1815− //printf("<%s>\n", str.data), fflush(stdout);
1816− dynarray_add(argv, argc, tcc_strdup(str.data));
1817− cstr_free(&str);
1818− ++ret;
1819− }
1820− return ret;
1821−}
1822−
1823−/* read list file */
1824−static int args_parser_listfile(TCCState *s,
1825− const char *filename, int optind, int *pargc, char ***pargv)
1826−{
1827− TCCState *s1 = s;
1828− int fd, i;
1829− char *p;
1830− int argc = 0;
1831− char **argv = NULL;
1832−
1833− fd = open(filename, O_RDONLY | O_BINARY);
1834− if (fd < 0)
1835− return tcc_error_noabort("listfile '%s' not found", filename);
1836−
1837− p = tcc_load_text(fd);
1838− for (i = 0; i < *pargc; ++i)
1839− if (i == optind)
1840− args_parser_make_argv(p, &argc, &argv);
1841− else
1842− dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
1843−
1844− tcc_free(p);
1845− dynarray_reset(&s->argv, &s->argc);
1846− *pargc = s->argc = argc, *pargv = s->argv = argv;
1847− return 0;
1848−}
1849−
18501786 #if defined TCC_TARGET_MACHO
18511787 static uint32_t parse_version(TCCState *s1, const char *version)
18521788 {
@@ -1867,46 +1803,79 @@ static uint32_t parse_version(TCCState *s1, const char *version) · 14 unmodified lines
18671803 }
18681804 #endif
18691805
1870−PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv, int optind)
1806+/* insert args from 'p' (separated by sep or ' ') into argv at position 'optind' */
1807+static void insert_args(TCCState *s1, char ***pargv, int *pargc, int optind, const char *p, int sep)
1808+{
1809+ int argc = 0;
1810+ char **argv = NULL;
1811+ int i;
1812+ for (i = 0; i < *pargc; ++i)
1813+ if (i == optind)
1814+ dynarray_split(&argv, &argc, p, sep);
1815+ else
1816+ dynarray_add(&argv, &argc, tcc_strdup((*pargv)[i]));
1817+ dynarray_reset(&s1->argv, &s1->argc);
1818+ *pargc = s1->argc = argc;
1819+ *pargv = s1->argv = argv;
1820+}
1821+
1822+static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
1823+{
1824+ struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
1825+ f->type = filetype;
1826+ strcpy(f->name, filename);
1827+ dynarray_add(&s->files, &s->nb_files, f);
1828+ if (filetype & AFF_TYPE_LIB)
1829+ ++s->nb_libraries;
1830+}
1831+
1832+/* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
1833+PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
18711834 {
18721835 TCCState *s1 = s;
18731836 const TCCOption *popt;
18741837 const char *optarg, *r;
18751838 const char *run = NULL;
18761839 int x;
1877− int tool = 0, arg_start = 0, noaction = optind;
1840+ int tool = 0, arg_start = 0, not_empty = 0, optind = 1;
18781841 char **argv = *pargv;
18791842 int argc = *pargc;
18801843
1881− cstr_reset(&s->linker_arg);
1844+ s->link_optind = s->link_argc;
18821845
18831846 while (optind < argc) {
18841847 r = argv[optind];
1885− if (r[0] == '@' && r[1] != '\0') {
1886− if (args_parser_listfile(s, r + 1, optind, &argc, &argv))
1887− return -1;
1848+ if (r[0] == '@' && r[1] != '\0') { /* read @listfile */
1849+ int fd; char *p;
1850+ fd = open(++r, O_RDONLY | O_BINARY);
1851+ if (fd < 0)
1852+ return tcc_error_noabort("listfile '%s' not found", r);
1853+ p = tcc_load_text(fd);
1854+ insert_args(s1, &argv, &argc, optind, p, 0);
1855+ close(fd), tcc_free(p);
18881856 continue;
18891857 }
18901858 optind++;
1891− if (tool) {
1892− if (r[0] == '-' && r[1] == 'v' && r[2] == 0)
1893− ++s->verbose;
1859+ if (tool) { /* ignore all except -v and @listfile */
1860+ s->verbose += !strcmp(r, "-v");
18941861 continue;
18951862 }
1896− if (r[0] != '-' || r[1] == '\0') {
1863+
1864+ if (r[0] != '-' || r[1] == '\0') { /* file or '-' (stdin) */
18971865 args_parser_add_file(s, r, s->filetype);
1866+ not_empty = 1;
1867+ dorun:
18981868 if (run) {
1899−dorun:
1869+ /* tcc -run <file> <args...> */
19001870 if (tcc_set_options(s, run))
19011871 return -1;
1902− arg_start = optind - 1;
1872+ arg_start = optind - 1; /* argv[0] will be <file> */
19031873 break;
19041874 }
19051875 continue;
19061876 }
1907−
1908− /* allow "tcc files... -run -- args ..." */
1909− if (r[1] == '-' && r[2] == '\0' && run)
1877+ /* Also allow "tcc <files...> -run -- <args...>" */
1878+ if (r[1] == '-' && r[2] == '\0')
19101879 goto dorun;
19111880
19121881 /* find option in table */
@@ -1921,7 +1890,6 @@ dorun: · 8 unmodified lines
19211890 if (popt->flags & TCC_OPTION_HAS_ARG) {
19221891 if (*r1 == '\0' && !(popt->flags & TCC_OPTION_NOSEP)) {
19231892 if (optind >= argc)
1924− arg_err:
19251893 return tcc_error_noabort("argument to '%s' is missing", r);
19261894 optarg = argv[optind++];
19271895 }
@@ -1931,12 +1899,6 @@ dorun: · 3 unmodified lines
19311899 }
19321900
19331901 switch(popt->index) {
1934− case TCC_OPTION_HELP:
1935− x = OPT_HELP;
1936− goto extra_action;
1937− case TCC_OPTION_HELP2:
1938− x = OPT_HELP2;
1939− goto extra_action;
19401902 case TCC_OPTION_I:
19411903 tcc_add_include_path(s, optarg);
19421904 break;
@@ -1952,11 +1914,9 @@ dorun: · 9 unmodified lines
19521914 case TCC_OPTION_B:
19531915 /* set tcc utilities path (mainly for tcc development) */
19541916 tcc_set_lib_path(s, optarg);
1955− ++noaction;
1956− break;
1917+ continue;
19571918 case TCC_OPTION_l:
19581919 args_parser_add_file(s, optarg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK));
1959− s->nb_libraries++;
19601920 break;
19611921 case TCC_OPTION_pthread:
19621922 s->option_pthread = 1;
@@ -2027,14 +1987,14 @@ dorun: · 64 unmodified lines
20271987 x = TCC_OUTPUT_DLL;
20281988 goto set_output_type;
20291989 case TCC_OPTION_soname:
2030− s->soname = tcc_strdup(optarg);
1990+ tcc_set_str(&s->soname, optarg);
20311991 break;
20321992 case TCC_OPTION_o:
20331993 if (s->outfile) {
20341994 tcc_warning("multiple -o option");
20351995 tcc_free(s->outfile);
20361996 }
2037− s->outfile = tcc_strdup(optarg);
1997+ tcc_set_str(&s->outfile, optarg);
20381998 break;
20391999 case TCC_OPTION_r:
20402000 /* generate a .o merging several output files */
@@ -2054,17 +2014,18 @@ dorun: · 13 unmodified lines
20542014 s->nostdlib = 1;
20552015 break;
20562016 case TCC_OPTION_run:
2057−#ifndef TCC_IS_NATIVE
2058− return tcc_error_noabort("-run is not available in a cross compiler");
2059−#else
2017+#ifdef TCC_IS_NATIVE
2018+ /* When from script "#!/usr/bin/tcc -run <options>",
2019+ argv[1] is "-run <options>" and argv[2] is <script-name> */
20602020 run = optarg;
20612021 x = TCC_OUTPUT_MEMORY;
20622022 goto set_output_type;
2023+#else
2024+ return tcc_error_noabort("-run is not available in a cross compiler");
20632025 #endif
20642026 case TCC_OPTION_v:
20652027 do ++s->verbose; while (*optarg++ == 'v');
2066− ++noaction;
2067− break;
2028+ continue;
20682029 case TCC_OPTION_f:
20692030 if (set_flag(s, options_f, optarg) < 0)
20702031 goto unsupported_option;
@@ -2086,7 +2047,7 @@ dorun: · 15 unmodified lines
20862047 goto unsupported_option;
20872048 if (PTR_SIZE != x/8)
20882049 return x;
2089− ++noaction;
2050+ continue;
20902051 }
20912052 break;
20922053 case TCC_OPTION_W:
@@ -2101,25 +2062,13 @@ dorun: · 8 unmodified lines
21012062 s->rdynamic = 1;
21022063 break;
21032064 case TCC_OPTION_Wl:
2104− if (s->linker_arg.size)
2105− ((char*)s->linker_arg.data)[s->linker_arg.size - 1] = ',';
2106− cstr_cat(&s->linker_arg, optarg, 0);
2107− x = tcc_set_linker(s, s->linker_arg.data);
2108− if (x)
2109− cstr_reset(&s->linker_arg);
2110− if (x < 0)
2065+ if (tcc_set_linker(s, optarg) < 0)
21112066 return -1;
21122067 break;
21132068 case TCC_OPTION_Wp:
2114− {
2115− char *p = tcc_strdup(optarg), *q = p;
2116− while (!!(q = strchr(q, ','))) *q++ = ' ';
2117− x = tcc_set_options(s, p);
2118− tcc_free(p);
2119− if (x < 0)
2120− return -1;
2069+ if (argv[0]) /* not with tcc_set_options() */
2070+ insert_args(s, &argv, &argc, --optind, optarg, ',');
21212071 break;
2122− }
21232072 case TCC_OPTION_E:
21242073 x = TCC_OUTPUT_PREPROCESS;
21252074 goto set_output_type;
@@ -2132,7 +2081,7 @@ dorun: · 6 unmodified lines
21322081 case TCC_OPTION_MM:
21332082 s->just_deps = 1;
21342083 if(!s->deps_outfile)
2135− s->deps_outfile = tcc_strdup("-");
2084+ tcc_set_str(&s->deps_outfile, "-");
21362085 // fall through
21372086 case TCC_OPTION_MMD:
21382087 s->gen_deps = 1;
@@ -2142,7 +2091,7 @@ dorun: · 3 unmodified lines
21422091 s->include_sys_deps = 1;
21432092 break;
21442093 case TCC_OPTION_MF:
2145− s->deps_outfile = tcc_strdup(optarg);
2094+ tcc_set_str(&s->deps_outfile, optarg);
21462095 break;
21472096 case TCC_OPTION_MP:
21482097 s->gen_phony_deps = 1;
@@ -2170,12 +2119,6 @@ dorun: · 21 unmodified lines
21702119 case TCC_OPTION_O:
21712120 s->optimize = isnum(optarg[0]) ? optarg[0]-'0' : 1 /* -O -Os */;
21722121 break;
2173− case TCC_OPTION_print_search_dirs:
2174− x = OPT_PRINT_DIRS;
2175− goto extra_action;
2176− case TCC_OPTION_impdef:
2177− x = OPT_IMPDEF;
2178− goto extra_action;
21792122 #if defined TCC_TARGET_MACHO
21802123 case TCC_OPTION_dynamiclib:
21812124 x = TCC_OUTPUT_DLL;
@@ -2187,7 +2130,7 @@ dorun: · 5 unmodified lines
21872130 case TCC_OPTION_undefined:
21882131 break;
21892132 case TCC_OPTION_install_name:
2190− s->install_name = tcc_strdup(optarg);
2133+ tcc_set_str(&s->install_name, optarg);
21912134 break;
21922135 case TCC_OPTION_compatibility_version:
21932136 s->compatibility_version = parse_version(s, optarg);
@@ -2196,11 +2139,23 @@ dorun: · 2 unmodified lines
21962139 s->current_version = parse_version(s, optarg);;
21972140 break;
21982141 #endif
2142+ case TCC_OPTION_HELP:
2143+ x = OPT_HELP;
2144+ goto extra_action;
2145+ case TCC_OPTION_HELP2:
2146+ x = OPT_HELP2;
2147+ goto extra_action;
2148+ case TCC_OPTION_print_search_dirs:
2149+ x = OPT_PRINT_DIRS;
2150+ goto extra_action;
2151+ case TCC_OPTION_impdef:
2152+ x = OPT_IMPDEF;
2153+ goto extra_action;
21992154 case TCC_OPTION_ar:
22002155 x = OPT_AR;
22012156 extra_action:
22022157 arg_start = optind - 1;
2203− if (arg_start != noaction)
2158+ if (not_empty)
22042159 return tcc_error_noabort("cannot parse %s here", r);
22052160 tool = x;
22062161 break;
@@ -2209,16 +2164,19 @@ unsupported_option: · 2 unmodified lines
22092164 tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
22102165 break;
22112166 }
2167+ not_empty = 1;
22122168 }
2213− if (s->linker_arg.size) {
2214− r = s->linker_arg.data;
2215− goto arg_err;
2216− }
2217− *pargc = argc - arg_start;
2218− *pargv = argv + arg_start;
2219− if (tool)
2169+
2170+ if (s->link_optind < s->link_argc)
2171+ return tcc_error_noabort("argument to '-Wl,%s' is missing", s->link_argv[s->link_optind]);
2172+ if (NULL == argv[0]) /* from tcc_set_options() */
2173+ return 0;
2174+ if (arg_start) {
2175+ *pargc = argc - arg_start;
2176+ *pargv = argv + arg_start;
22202177 return tool;
2221− if (optind != noaction)
2178+ }
2179+ if (not_empty)
22222180 return 0;
22232181 if (s->verbose == 2)
22242182 return OPT_PRINT_DIRS;
@@ -2231,10 +2189,11 @@ LIBTCCAPI int tcc_set_options(TCCState *s, const char *r) · 6 unmodified lines
22312189 {
22322190 char **argv = NULL;
22332191 int argc = 0, ret;
2234− args_parser_make_argv(r, &argc, &argv);
2235− ret = tcc_parse_args(s, &argc, &argv, 0);
2192+ dynarray_add(&argv, &argc, 0);
2193+ dynarray_split(&argv, &argc, r, 0);
2194+ ret = tcc_parse_args(s, &argc, &argv);
22362195 dynarray_reset(&argv, &argc);
2237− return ret < 0 ? ret : 0;
2196+ return ret;
22382197 }
22392198
22402199 PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time)
@@ -2267,9 +2226,3 @@ PUB_FUNC void tcc_print_stats(TCCState *s1, unsigned total_time) · 26 unmodified lines
22672226 fprintf(stderr, " %d max (bytes)\n", mem_max_size);
22682227 #endif
22692228 }
2270−
2271−#if ONE_SOURCE
2272−# undef malloc
2273−# undef realloc
2274−# undef free
2275−#endif
tcc-doc.texi+12−10
@@ -185,16 +185,6 @@ Show included files. As sole argument, print search dirs. -vvv shows tries too · 184 unmodified lines
185185 @item -bench
186186 Display compilation statistics.
187187
188−@item -pthread
189−Preprocess with @option{-D_REENTRANT}, link with @option{-lpthread}.
190−
191−@item -On
192−Pretend to optimise: set @option{-D__OPTIMIZE__} to the numeric value of n.
193−Note that TCC performs no additional optimisation.
194−
195−@item -dt
196−With @option{-run}/@option{-E}: auto-define 'test_...' macros
197−
198188 @end table
199189
200190 Preprocessor options:
@@ -441,6 +431,12 @@ gnu11; @code{199901} otherwise. · 240 unmodified lines
441431 @item -x[c|a|b|n]
442432 Specify content of next input file: respectively C, assembly, binary, or none.
443433
434+@item -O[n]
435+Same as @option{-D__OPTIMIZE__} except for -O0.
436+
437+@item -pthread
438+Preprocess with @option{-D_REENTRANT}, link with @option{-lpthread}.
439+
444440 @item -M
445441 Just output makefile fragment with dependencies
446442
@@ -456,6 +452,9 @@ Like -MD except mention only user header files, not system header files. · 9 unmodified lines
456452 @item -MF depfile
457453 Use @file{depfile} as output for -MD.
458454
455+@item -MP
456+Mention all dependencies as targets too.
457+
459458 @item -print-search-dirs
460459 Print the configured installation directory and a list of library
461460 and include directories tcc will search.
@@ -463,6 +462,9 @@ and include directories tcc will search. · 1 unmodified line
463462 @item -dumpversion
464463 Print version.
465464
465+@item -dt
466+With @option{-run}/@option{-E}: auto-define 'test_...' macros
467+
466468 @end table
467469
468470 Target specific options:
tcc.c+6−4
@@ -158,7 +158,7 @@ static const char help2[] = · 157 unmodified lines
158158 #endif
159159 " -Bsymbolic set DT_SYMBOLIC elf tag\n"
160160 " -oformat=[elf32/64-* binary] set executable output format\n"
161− " -init= -fini= -Map= -as-needed -O (ignored)\n"
161+ " -init= -fini= -Map= -as-needed -O -z= (ignored)\n"
162162 "Predefined macros:\n"
163163 " tcc -E -dM - < /dev/null\n"
164164 #endif
@@ -221,7 +221,7 @@ static void print_search_dirs(TCCState *s) · 56 unmodified lines
221221 print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
222222 print_dirs("libraries", s->library_paths, s->nb_library_paths);
223223 printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1);
224−#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO
224+#ifdef TCC_TARGET_UNIX
225225 print_dirs("crt", s->crt_paths, s->nb_crt_paths);
226226 printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
227227 #endif
@@ -253,7 +253,9 @@ static char *default_outputfile(TCCState *s, const char *first_file) · 25 unmodified lines
253253
254254 if (first_file && strcmp(first_file, "-"))
255255 name = tcc_basename(first_file);
256− snprintf(buf, sizeof(buf), "%s", name);
256+ if (strlen(name) + 4 >= sizeof buf)
257+ name = "a";
258+ strcpy(buf, name);
257259 ext = tcc_fileextension(buf);
258260 #ifdef TCC_TARGET_PE
259261 if (s->output_type == TCC_OUTPUT_DLL)
@@ -293,7 +295,7 @@ int main(int argc0, char **argv0) · 33 unmodified lines
293295 redo:
294296 argc = argc0, argv = argv0;
295297 s = s1 = tcc_new();
296− opt = tcc_parse_args(s, &argc, &argv, 1);
298+ opt = tcc_parse_args(s, &argc, &argv);
297299 if (opt < 0)
298300 return 1;
299301
tcc.h+12−11
@@ -217,6 +217,8 @@ extern long double strtold (const char *__nptr, char **__endptr); · 216 unmodified lines
217217
218218 #if defined TCC_TARGET_PE || defined TCC_TARGET_MACHO
219219 # define ELF_OBJ_ONLY /* create elf .o but native executables */
220+#else
221+# define TCC_TARGET_UNIX 1
220222 #endif
221223
222224 /* No ten-byte long doubles on window and macos except in
@@ -919,8 +921,6 @@ struct TCCState { · 696 unmodified lines
919921 /* debug state */
920922 struct _tccdbg *dState;
921923
922− /* Is there a new undefined sym since last new_undef_sym() */
923− int new_undef_sym;
924924 /* extra attributes (eg. GOT/PLT value) for symtab symbols */
925925 struct sym_attr *sym_attrs;
926926 int nb_sym_attrs;
@@ -988,7 +988,7 @@ struct TCCState { · 61 unmodified lines
988988 unsigned int total_output[4];
989989
990990 /* used by tcc_load_ldscript */
991− int fd, cc;
991+ unsigned char *ld_p; /* text pointer */
992992
993993 /* for warnings/errors for object files */
994994 const char *current_filename;
@@ -1001,7 +1001,9 @@ struct TCCState { · 6 unmodified lines
10011001 char *deps_outfile; /* option -MF */
10021002 int argc;
10031003 char **argv;
1004− CString linker_arg; /* collect -Wl options */
1004+ /* -Wl options */
1005+ char **link_argv;
1006+ int link_argc, link_optind;
10051007 };
10061008
10071009 struct filespec {
@@ -1195,7 +1197,7 @@ ST_DATA int g_debug; · 187 unmodified lines
11951197 /* public functions currently used by the tcc main function */
11961198 ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s);
11971199 ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s);
1198−ST_FUNC char *pstrncpy(char *out, const char *in, size_t num);
1200+ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num);
11991201 PUB_FUNC char *tcc_basename(const char *name);
12001202 PUB_FUNC char *tcc_fileextension (const char *name);
12011203
@@ -1265,7 +1267,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 63 unmodified lines
12651267 #define AFF_TYPE_ASM 2
12661268 #define AFF_TYPE_ASMPP 4
12671269 #define AFF_TYPE_LIB 8
1268−#define AFF_TYPE_MASK (15 | AFF_TYPE_BIN)
1270+#define AFF_TYPE_MASK (7 | AFF_TYPE_BIN)
12691271 /* values from tcc_object_type(...) */
12701272 #define AFF_BINTYPE_REL 1
12711273 #define AFF_BINTYPE_DYN 2
@@ -1274,6 +1276,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 2 unmodified lines
12741276
12751277 /* return value of tcc_add_file_internal(): 0, -1, or FILE_NOT_FOUND */
12761278 #define FILE_NOT_FOUND -2
1279+#define FILE_NOT_RECOGNIZED -3 /* unrecognized file type */
12771280
12781281 #ifndef ELF_OBJ_ONLY
12791282 ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
@@ -1289,7 +1292,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1); · 9 unmodified lines
12891292 ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
12901293 PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
12911294 PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
1292−PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind);
1295+PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv);
12931296 #ifdef _WIN32
12941297 ST_FUNC char *normalize_slashes(char *path);
12951298 #endif
@@ -1571,7 +1574,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1); · 275 unmodified lines
15711574
15721575 /* ------------ xxx-link.c ------------ */
15731576
1574−#if !defined ELF_OBJ_ONLY || defined TCC_TARGET_MACHO
1577+#ifndef TCC_TARGET_PE
15751578 ST_FUNC int code_reloc (int reloc_type);
15761579 ST_FUNC int gotplt_entry_type (int reloc_type);
15771580 /* Whether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so
@@ -1583,13 +1586,11 @@ enum gotplt_entry { · 5 unmodified lines
15831586 ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */
15841587 };
15851588 #define NEED_RELOC_TYPE
1586−
15871589 #if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE
15881590 ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr);
15891591 ST_FUNC void relocate_plt(TCCState *s1);
15901592 ST_FUNC void build_got_entries(TCCState *s1, int got_sym); /* in tccelf.c */
15911593 #define NEED_BUILD_GOT
1592−
15931594 #endif
15941595 #endif
15951596
@@ -1809,7 +1810,7 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev); · 213 unmodified lines
18091810 ST_FUNC int macho_load_tbd(TCCState *s1, int fd, const char *filename, int lev);
18101811 #ifdef TCC_IS_NATIVE
18111812 ST_FUNC void tcc_add_macos_sdkpath(TCCState* s);
1812−ST_FUNC const char* macho_tbd_soname(const char* filename);
1813+ST_FUNC char* macho_tbd_soname(int fd);
18131814 #endif
18141815 #endif
18151816 /* ------------ tccrun.c ----------------- */
tccelf.c+94−114
@@ -526,6 +526,24 @@ LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) · 525 unmodified lines
526526 return addr == -1 ? NULL : (void*)(uintptr_t)addr;
527527 }
528528
529+LIBTCCAPI int tcc_add_symbol(TCCState *s1, const char *name, const void *val)
530+{
531+#ifdef TCC_TARGET_PE
532+ /* On x86_64 'val' might not be reachable with a 32bit offset.
533+ So it is handled here as if it were in a DLL. */
534+ pe_putimport(s1, 0, name, (uintptr_t)val);
535+#else
536+ char buf[256];
537+ if (s1->leading_underscore) {
538+ buf[0] = '_';
539+ pstrcpy(buf + 1, sizeof(buf) - 1, name);
540+ name = buf;
541+ }
542+ set_global_sym(s1, name, NULL, (addr_t)(uintptr_t)val); /* NULL: SHN_ABS */
543+#endif
544+ return 0;
545+}
546+
529547 /* list elf symbol names and values */
530548 ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
531549 void (*symbol_cb)(void *ctx, const char *name, const void *val))
@@ -733,7 +751,6 @@ ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, · 201 unmodified lines
733751 do_patch:
734752 esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
735753 esym->st_shndx = shndx;
736− s1->new_undef_sym = 1;
737754 esym->st_value = value;
738755 esym->st_size = size;
739756 }
@@ -1058,15 +1075,16 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) · 318 unmodified lines
10581075 if (do_resolve) {
10591076 #if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
10601077 /* dlsym() needs the undecorated name. */
1061− void *addr = dlsym(RTLD_DEFAULT, &name[s1->leading_underscore]);
1062−#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD || TARGETOS_ANDROID
1078+ const char *name_ud = &name[s1->leading_underscore];
1079+ void *addr = NULL;
1080+ if (!s1->nostdlib)
1081+ addr = dlsym(RTLD_DEFAULT, name_ud);
10631082 if (addr == NULL) {
10641083 int i;
10651084 for (i = 0; i < s1->nb_loaded_dlls; i++)
1066− if ((addr = dlsym(s1->loaded_dlls[i]->handle, name)))
1085+ if ((addr = dlsym(s1->loaded_dlls[i]->handle, name_ud)))
10671086 break;
10681087 }
1069−#endif
10701088 if (addr) {
10711089 sym->st_value = (addr_t) addr;
10721090 #ifdef DEBUG_RELOC
@@ -1691,7 +1709,7 @@ static void tcc_tcov_add_file(TCCState *s1, const char *filename) · 618 unmodified lines
16911709 set_local_sym(s1, &"___tcov_data"[!s1->leading_underscore], tcov_section, 0);
16921710 }
16931711
1694−#if !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO
1712+#ifdef TCC_TARGET_UNIX
16951713 /* add libc crt1/crti objects */
16961714 ST_FUNC void tccelf_add_crtbegin(TCCState *s1)
16971715 {
@@ -1750,7 +1768,7 @@ ST_FUNC void tccelf_add_crtend(TCCState *s1) · 52 unmodified lines
17501768 tcc_add_crt(s1, "crtn.o");
17511769 #endif
17521770 }
1753−#endif /* !defined TCC_TARGET_PE && !defined TCC_TARGET_MACHO */
1771+#endif /* TCC_TARGET_UNIX */
17541772
17551773 #ifndef TCC_TARGET_PE
17561774 /* add tcc runtime libraries */
@@ -3789,19 +3807,15 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 2032 unmodified lines
37893807
37903808 #define LD_TOK_NAME 256
37913809 #define LD_TOK_EOF (-1)
3792−
37933810 static int ld_inp(TCCState *s1)
37943811 {
3795− char b;
3796− if (s1->cc != -1) {
3797− int c = s1->cc;
3798− s1->cc = -1;
3799− return c;
3800− }
3801− if (1 == read(s1->fd, &b, 1))
3802− return b;
3803− return CH_EOF;
3812+ int c = *s1->ld_p;
3813+ if (c == 0)
3814+ return CH_EOF;
3815+ ++s1->ld_p;
3816+ return c;
38043817 }
3818+#define ld_unget(s1, ch) if (ch != CH_EOF) --s1->ld_p
38053819
38063820 /* return next ld script token */
38073821 static int ld_next(TCCState *s1, char *name, int name_size)
@@ -3811,6 +3825,7 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 3 unmodified lines
38113825
38123826 redo:
38133827 ch = ld_inp(s1);
3828+ q = name, *q++ = ch;
38143829 switch(ch) {
38153830 case ' ':
38163831 case '\t':
@@ -3829,8 +3844,6 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 12 unmodified lines
38293844 }
38303845 goto redo;
38313846 } else {
3832− q = name;
3833− *q++ = '/';
38343847 goto parse_name;
38353848 }
38363849 break;
@@ -3889,13 +3902,14 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 52 unmodified lines
38893902 case 'X':
38903903 case 'Y':
38913904 case 'Z':
3905+ case '-':
38923906 case '_':
38933907 case '.':
38943908 case '$':
38953909 case '~':
3896− q = name;
3897− parse_name:
38983910 for(;;) {
3911+ ch = ld_inp(s1);
3912+ parse_name:
38993913 if (!((ch >= 'a' && ch <= 'z') ||
39003914 (ch >= 'A' && ch <= 'Z') ||
39013915 (ch >= '0' && ch <= '9') ||
@@ -3904,10 +3918,8 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 2 unmodified lines
39043918 if ((q - name) < name_size - 1) {
39053919 *q++ = ch;
39063920 }
3907− ch = ld_inp(s1);
39083921 }
3909− s1->cc = ch;
3910− *q = '\0';
3922+ ld_unget(s1, ch);
39113923 c = LD_TOK_NAME;
39123924 break;
39133925 case CH_EOF:
@@ -3917,93 +3929,71 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 3 unmodified lines
39173929 c = ch;
39183930 break;
39193931 }
3932+ *q = '\0';
39203933 return c;
39213934 }
39223935
39233936 static int ld_add_file(TCCState *s1, const char filename[])
39243937 {
3925− if (filename[0] == '/') {
3926− if (CONFIG_SYSROOT[0] == '\0'
3927− && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0)
3928− return 0;
3929− filename = tcc_basename(filename);
3938+ if (filename[0] == '-' && filename[1] == 'l')
3939+ return tcc_add_library(s1, filename + 2);
3940+ if (CONFIG_SYSROOT[0] != '\0') {
3941+ /* lookup via library paths */
3942+ int ret = tcc_add_dll(s1, tcc_basename(filename), 0);
3943+ if (ret != FILE_NOT_FOUND)
3944+ return ret;
39303945 }
3931− return tcc_add_dll(s1, filename, AFF_PRINT_ERROR);
3946+ return tcc_add_file_internal(s1, filename, AFF_PRINT_ERROR);
39323947 }
39333948
3934−static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
3949+/* did static libraries add new undefined symbols? */
3950+static int new_undef_sym(TCCState *s1, int sym_offset)
39353951 {
3936− char filename[1024], libname[1016];
3937− int t, group, nblibs = 0, ret = 0;
3938− char **libs = NULL;
3952+ while (sym_offset < s1->symtab->data_offset) {
3953+ ElfW(Sym) *esym = (void*)(s1->symtab->data + sym_offset);
3954+ if (esym->st_shndx == SHN_UNDEF)
3955+ return 1;
3956+ sym_offset += sizeof (ElfW(Sym));
3957+ }
3958+ return 0;
3959+}
3960+
3961+static int ld_add_file_list(TCCState *s1, const char *cmd)
3962+{
3963+ char filename[1024];
3964+ int t, c, sym_offset, ret = 0;
3965+ unsigned char *pos = s1->ld_p;
3966+
3967+repeat:
3968+ s1->ld_p = pos;
3969+ sym_offset = s1->symtab->data_offset;
3970+ c = cmd[0];
39393971
3940− group = !strcmp(cmd, "GROUP");
3941− if (!as_needed)
3942− s1->new_undef_sym = 0;
39433972 t = ld_next(s1, filename, sizeof(filename));
3944− if (t != '(') {
3945− ret = tcc_error_noabort("( expected");
3946− goto lib_parse_error;
3947− }
3973+ if (t != '(')
3974+ return tcc_error_noabort("expected '(' after %s", cmd);
39483975 t = ld_next(s1, filename, sizeof(filename));
39493976 for(;;) {
3950− libname[0] = '\0';
39513977 if (t == LD_TOK_EOF) {
3952− ret = tcc_error_noabort("unexpected end of file");
3953− goto lib_parse_error;
3978+ return tcc_error_noabort("unexpected end of file");
39543979 } else if (t == ')') {
39553980 break;
3956− } else if (t == '-') {
3957− t = ld_next(s1, filename, sizeof(filename));
3958− if ((t != LD_TOK_NAME) || (filename[0] != 'l')) {
3959− ret = tcc_error_noabort("library name expected");
3960− goto lib_parse_error;
3961− }
3962− pstrcpy(libname, sizeof libname, &filename[1]);
3963− if (s1->static_link) {
3964− snprintf(filename, sizeof filename, "lib%s.a", libname);
3965− } else {
3966− snprintf(filename, sizeof filename, "lib%s.so", libname);
3967− }
39683981 } else if (t != LD_TOK_NAME) {
3969− ret = tcc_error_noabort("filename expected");
3970− goto lib_parse_error;
3971− }
3972− if (!strcmp(filename, "AS_NEEDED")) {
3973− ret = ld_add_file_list(s1, cmd, 1);
3974− if (ret)
3975− goto lib_parse_error;
3976− } else {
3977− /* TODO: Implement AS_NEEDED support. */
3978− /* DT_NEEDED is not used any more so ignore as_needed */
3979− if (1 || !as_needed) {
3980− ret = ld_add_file(s1, filename);
3981− if (ret)
3982− goto lib_parse_error;
3983− if (group) {
3984− /* Add the filename *and* the libname to avoid future conversions */
3985− dynarray_add(&libs, &nblibs, tcc_strdup(filename));
3986− if (libname[0] != '\0')
3987− dynarray_add(&libs, &nblibs, tcc_strdup(libname));
3988− }
3989− }
3982+ return tcc_error_noabort("unexpected token '%c'", t);
3983+ } else if (!strcmp(filename, "AS_NEEDED")) {
3984+ ret = ld_add_file_list(s1, filename);
3985+ } else if (c == 'I' || c == 'G' || c == 'A') {
3986+ ret = ld_add_file(s1, filename);
39903987 }
3988+ if (ret)
3989+ return -1;
39913990 t = ld_next(s1, filename, sizeof(filename));
3992− if (t == ',') {
3991+ if (t == ',')
39933992 t = ld_next(s1, filename, sizeof(filename));
3994− }
39953993 }
3996− if (group && !as_needed) {
3997− while (s1->new_undef_sym) {
3998− int i;
3999− s1->new_undef_sym = 0;
4000− for (i = 0; i < nblibs; i ++)
4001− ld_add_file(s1, libs[i]);
4002− }
4003− }
4004−lib_parse_error:
4005− dynarray_reset(&libs, &nblibs);
4006− return ret;
3994+ if (c == 'G' && new_undef_sym(s1, sym_offset))
3995+ goto repeat;
3996+ return 0;
40073997 }
40083998
40093999 /* interpret a subset of GNU ldscripts to handle the dummy libc.so
@@ -4011,40 +4001,30 @@ lib_parse_error: · 1 unmodified line
40114001 ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd)
40124002 {
40134003 char cmd[64];
4014− char filename[1024];
4015− int t, ret;
4004+ int t, ret = FILE_NOT_RECOGNIZED;
4005+ unsigned char *text_ptr, *saved_ptr;
40164006
4017− s1->fd = fd;
4018− s1->cc = -1;
4007+ saved_ptr = s1->ld_p;
4008+ s1->ld_p = text_ptr = (void*)tcc_load_text(fd);
40194009 for(;;) {
40204010 t = ld_next(s1, cmd, sizeof(cmd));
40214011 if (t == LD_TOK_EOF)
4022− return 0;
4023− else if (t != LD_TOK_NAME)
4024− return -1;
4012+ break;
40254013 if (!strcmp(cmd, "INPUT") ||
40264014 !strcmp(cmd, "GROUP")) {
4027− ret = ld_add_file_list(s1, cmd, 0);
4028− if (ret)
4029− return ret;
4015+ ret = ld_add_file_list(s1, cmd);
40304016 } else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
40314017 !strcmp(cmd, "TARGET")) {
40324018 /* ignore some commands */
4033− t = ld_next(s1, cmd, sizeof(cmd));
4034− if (t != '(')
4035− return tcc_error_noabort("( expected");
4036− for(;;) {
4037− t = ld_next(s1, filename, sizeof(filename));
4038− if (t == LD_TOK_EOF) {
4039− return tcc_error_noabort("unexpected end of file");
4040− } else if (t == ')') {
4041− break;
4042− }
4043− }
4044− } else {
4045− return -1;
4019+ ret = ld_add_file_list(s1, cmd);
4020+ } else if (0 == ret) {
4021+ ret = tcc_error_noabort("unexpected '%s'", cmd);
40464022 }
4023+ if (ret)
4024+ break;
40474025 }
4048− return 0;
4026+ tcc_free(text_ptr);
4027+ s1->ld_p = saved_ptr;
4028+ return ret;
40494029 }
40504030 #endif /* !ELF_OBJ_ONLY */
tccgen.c+6−1
@@ -2401,10 +2401,15 @@ static void gen_opic(int op) · 2400 unmodified lines
24012401 (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) {
24022402 /* filter out NOP operations like x*1, x-0, x&-1... */
24032403 vtop--;
2404− } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) {
2404+ } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV || op == TOK_UMOD)) {
24052405 /* try to use shifts instead of muls or divs */
24062406 if (l2 > 0 && (l2 & (l2 - 1)) == 0) {
24072407 int n = -1;
2408+ if (op == TOK_UMOD) {
2409+ vtop->c.i = l2 - 1;
2410+ op = '&';
2411+ goto general_case;
2412+ }
24082413 while (l2) {
24092414 l2 >>= 1;
24102415 n++;
tccmacho.c+4−8
@@ -2195,9 +2195,6 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 2194 unmodified lines
21952195 tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
21962196 return -1;
21972197 }
2198− if (s1->verbose)
2199− printf("<- %s\n", filename);
2200−
22012198 tcc_add_runtime(s1);
22022199 tcc_macho_add_destructor(s1);
22032200 resolve_common_syms(s1);
@@ -2222,6 +2219,8 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 18 unmodified lines
22222219 bind_rebase_import(s1, &mo);
22232220 #endif
22242221 convert_symbols(s1, &mo);
2222+ if (s1->verbose)
2223+ printf("<- %s\n", filename);
22252224 macho_write(s1, &mo, fp);
22262225 }
22272226
@@ -2291,12 +2290,9 @@ ST_FUNC void tcc_add_macos_sdkpath(TCCState* s) · 63 unmodified lines
22912290 cstr_free(&path);
22922291 }
22932292
2294−ST_FUNC const char* macho_tbd_soname(const char* filename) {
2293+ST_FUNC char* macho_tbd_soname(int fd) {
22952294 char *soname, *data, *pos;
2296− const char *ret = filename;
2297−
2298− int fd = open(filename,O_RDONLY);
2299− if (fd<0) return ret;
2295+ char *ret = 0;
23002296 pos = data = tcc_load_text(fd);
23012297 if (!tbd_parse_movepast("install-name: ")) goto the_end;
23022298 tbd_parse_skipws;
tccpp.c+2−2
@@ -1354,7 +1354,7 @@ static int parse_include(TCCState *s1, int do_next, int test) · 1353 unmodified lines
13541354 cstr_reset(&tokcstr);
13551355 file->buf_ptr = parse_pp_string(file->buf_ptr, c == '<' ? '>' : c, &tokcstr);
13561356 i = tokcstr.size;
1357− pstrncpy(name, tokcstr.data, i >= sizeof name ? sizeof name - 1 : i);
1357+ pstrncpy(name, sizeof name, tokcstr.data, i);
13581358 next_nomacro();
13591359 } else {
13601360 /* computed #include : concatenate tokens until result is one of
@@ -1395,7 +1395,7 @@ static int parse_include(TCCState *s1, int do_next, int test) · 34 unmodified lines
13951395 if (c != '\"')
13961396 continue;
13971397 p = file->true_filename;
1398− pstrncpy(buf, p, tcc_basename(p) - p);
1398+ pstrncpy(buf, sizeof buf, p, tcc_basename(p) - p);
13991399 } else {
14001400 int j = i - 2, k = j - s1->nb_include_paths;
14011401 if (k < 0)
tccrun.c+2−2
@@ -221,7 +221,7 @@ LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv) · 220 unmodified lines
221221
222222 tcc_add_symbol(s1, "__rt_exit", rt_exit);
223223 if (s1->nostdlib) {
224− s1->run_main = top_sym = "_start";
224+ s1->run_main = top_sym = s1->elf_entryname ? s1->elf_entryname : "_start";
225225 } else {
226226 tcc_add_support(s1, "runmain.o");
227227 s1->run_main = "_runmain";
@@ -421,7 +421,7 @@ redo: · 193 unmodified lines
421421 }
422422
423423 /* relocate symbols */
424− relocate_syms(s1, s1->symtab, !(s1->nostdlib));
424+ relocate_syms(s1, s1->symtab, 1);
425425 /* relocate sections */
426426 #ifdef TCC_TARGET_PE
427427 s1->pe_imagebase = mem;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t