| @@ -259,6 +259,7 @@ ST_FUNC int add_elf_sym(Section *s, uplong value, unsigned long size, · 258 unmodified lines |
| 259 | 259 | do_patch: |
| 260 | 260 | esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); |
| 261 | 261 | esym->st_shndx = sh_num; |
| 262 | + new_undef_sym = 1; |
| 262 | 263 | esym->st_value = value; |
| 263 | 264 | esym->st_size = size; |
| 264 | 265 | esym->st_other = other; |
| @@ -2808,9 +2809,77 @@ static int ld_next(TCCState *s1, char *name, int name_size) · 2543 unmodified lines |
| 2808 | 2809 | return c; |
| 2809 | 2810 | } |
| 2810 | 2811 | |
| 2812 | +/* |
| 2813 | + * Extract the library name from the file name |
| 2814 | + * Return 0 if the file isn't a library |
| 2815 | + * |
| 2816 | + * /!\ No test on filename capacity, be careful |
| 2817 | + */ |
| 2818 | +static int filename_to_libname(TCCState *s1, char filename[], char libname[]) |
| 2819 | +{ |
| 2820 | + char *ext, *base; |
| 2821 | + int libprefix; |
| 2822 | + |
| 2823 | + /* already converted to library name */ |
| 2824 | + if (filename[0] == '\0') |
| 2825 | + return 1; |
| 2826 | + base = tcc_basename(filename); |
| 2827 | + if (base != filename) |
| 2828 | + return 0; |
| 2829 | + ext = strrchr(base, '.'); |
| 2830 | + if (ext == NULL) |
| 2831 | + return 0; |
| 2832 | + ext++; |
| 2833 | + libprefix = !strncmp(filename, "lib", 3); |
| 2834 | + if (!s1->static_link) { |
| 2835 | +#ifdef TCC_TARGET_PE |
| 2836 | + if (!strncmp(ext, "def", 3)) { |
| 2837 | + *(--ext) = '\0'; |
| 2838 | + strcpy(libname, filename); |
| 2839 | + *ext = '.'; |
| 2840 | + return 1; |
| 2841 | + } |
| 2842 | +#else |
| 2843 | + if (libprefix && (!strncmp(ext, "so", 2))) { |
| 2844 | + *(--ext) = '\0'; |
| 2845 | + strcpy(libname, filename + 3); |
| 2846 | + *ext = '.'; |
| 2847 | + return 1; |
| 2848 | + } |
| 2849 | +#endif |
| 2850 | + } else { |
| 2851 | + if (libprefix && (!strncmp(ext, "a", 1))) { |
| 2852 | + *(--ext) = '\0'; |
| 2853 | + strcpy(libname, filename + 3); |
| 2854 | + *ext = '.'; |
| 2855 | + return 1; |
| 2856 | + } |
| 2857 | + } |
| 2858 | + return 0; |
| 2859 | +} |
| 2860 | + |
| 2861 | +/* |
| 2862 | + * Extract the file name from the library name |
| 2863 | + * |
| 2864 | + * /!\ No test on filename capacity, be careful |
| 2865 | + */ |
| 2866 | +static void libname_to_filename(TCCState *s1, char libname[], char filename[]) |
| 2867 | +{ |
| 2868 | + if (!s1->static_link) { |
| 2869 | +#ifdef TCC_TARGET_PE |
| 2870 | + snprintf(filename, strlen(libname) + 5, "%s.def", libname); |
| 2871 | +#else |
| 2872 | + snprintf(filename, strlen(libname) + 7, "lib%s.so", libname); |
| 2873 | +#endif |
| 2874 | + } else { |
| 2875 | + snprintf(filename, strlen(libname) + 6, "lib%s.a", libname); |
| 2876 | + } |
| 2877 | +} |
| 2878 | + |
| 2811 | 2879 | static int ld_add_file_list(TCCState *s1, int as_needed) |
| 2812 | 2880 | { |
| 2813 | 2881 | char filename[1024]; |
| 2882 | + char libname[1024]; |
| 2814 | 2883 | int t, ret; |
| 2815 | 2884 | |
| 2816 | 2885 | t = ld_next(s1, filename, sizeof(filename)); |
| @@ -2818,11 +2887,20 @@ static int ld_add_file_list(TCCState *s1, int as_needed) · 1 unmodified line |
| 2818 | 2887 | expect("("); |
| 2819 | 2888 | t = ld_next(s1, filename, sizeof(filename)); |
| 2820 | 2889 | for(;;) { |
| 2890 | + libname[0] = '\0'; |
| 2821 | 2891 | if (t == LD_TOK_EOF) { |
| 2822 | 2892 | error_noabort("unexpected end of file"); |
| 2823 | 2893 | return -1; |
| 2824 | 2894 | } else if (t == ')') { |
| 2825 | 2895 | break; |
| 2896 | + } else if (t == '-') { |
| 2897 | + t = ld_next(s1, filename, sizeof(filename)); |
| 2898 | + if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { |
| 2899 | + error_noabort("library name expected"); |
| 2900 | + return -1; |
| 2901 | + } |
| 2902 | + strcpy(libname, &filename[1]); |
| 2903 | + libname_to_filename(s1, libname, filename); |
| 2826 | 2904 | } else if (t != LD_TOK_NAME) { |
| 2827 | 2905 | error_noabort("filename expected"); |
| 2828 | 2906 | return -1; |
| @@ -2833,8 +2911,15 @@ static int ld_add_file_list(TCCState *s1, int as_needed) · 4 unmodified lines |
| 2833 | 2911 | return ret; |
| 2834 | 2912 | } else { |
| 2835 | 2913 | /* TODO: Implement AS_NEEDED support. Ignore it for now */ |
| 2836 | | − if (!as_needed) |
| 2837 | | − tcc_add_file(s1, filename); |
| 2914 | + if (!as_needed) { |
| 2915 | + ret = tcc_add_file_internal(s1, filename, 0); |
| 2916 | + if (ret) { |
| 2917 | + if (filename_to_libname(s1, filename, libname)) |
| 2918 | + ret = tcc_add_library(s1, libname); |
| 2919 | + if (ret) |
| 2920 | + return ret; |
| 2921 | + } |
| 2922 | + } |
| 2838 | 2923 | } |
| 2839 | 2924 | t = ld_next(s1, filename, sizeof(filename)); |
| 2840 | 2925 | if (t == ',') { |
| @@ -2844,6 +2929,14 @@ static int ld_add_file_list(TCCState *s1, int as_needed) · 3 unmodified lines |
| 2844 | 2929 | return 0; |
| 2845 | 2930 | } |
| 2846 | 2931 | |
| 2932 | +static int new_undef_syms(void) |
| 2933 | +{ |
| 2934 | + int ret = 0; |
| 2935 | + ret = new_undef_sym; |
| 2936 | + new_undef_sym = 0; |
| 2937 | + return ret; |
| 2938 | +} |
| 2939 | + |
| 2847 | 2940 | /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
| 2848 | 2941 | files */ |
| 2849 | 2942 | ST_FUNC int tcc_load_ldscript(TCCState *s1) |
| @@ -2862,7 +2955,24 @@ ST_FUNC int tcc_load_ldscript(TCCState *s1) · 12 unmodified lines |
| 2862 | 2955 | return -1; |
| 2863 | 2956 | if (!strcmp(cmd, "INPUT") || |
| 2864 | 2957 | !strcmp(cmd, "GROUP")) { |
| 2865 | | − ret = ld_add_file_list(s1, 0); |
| 2958 | + if (!strcmp(cmd, "GROUP")) { |
| 2959 | + BufferedFile *buf_state; |
| 2960 | + int off; |
| 2961 | + |
| 2962 | + buf_state = tcc_save_buffer_state(&off); |
| 2963 | + new_undef_syms(); |
| 2964 | + ret = ld_add_file_list(s1, 0); |
| 2965 | + if (ret) |
| 2966 | + goto free_bufstate; |
| 2967 | + while (!ret && new_undef_syms()) { |
| 2968 | + tcc_load_buffer_state(buf_state, off); |
| 2969 | + ret = ld_add_file_list(s1, 0); |
| 2970 | + } |
| 2971 | + free_bufstate: |
| 2972 | + tcc_free_buffer_state(buf_state); |
| 2973 | + } else { |
| 2974 | + ret = ld_add_file_list(s1, 0); |
| 2975 | + } |
| 2866 | 2976 | if (ret) |
| 2867 | 2977 | return ret; |
| 2868 | 2978 | } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |