@@ -380,17 +380,67 @@ static const char* find_libc_crt_dir(const char* sysroot,
380380 return NULL ;
381381}
382382
383- static const char * find_ponyc_crt_dir ( ast_t * program, pass_opt_t * opt )
383+ static uint16_t expected_elf_machine ( compile_t * c )
384384{
385- (void )opt;
385+ llvm::Triple triple (c->opt ->triple );
386+
387+ switch (triple.getArch ())
388+ {
389+ case llvm::Triple::x86_64: return 62 ; // EM_X86_64
390+ case llvm::Triple::aarch64: return 183 ; // EM_AARCH64
391+ case llvm::Triple::riscv64: return 243 ; // EM_RISCV
392+ case llvm::Triple::riscv32: return 243 ; // EM_RISCV
393+ case llvm::Triple::arm:
394+ case llvm::Triple::thumb: return 40 ; // EM_ARM
395+ default : return 0 ;
396+ }
397+ }
398+
399+ static bool elf_matches_target (const char * path, uint16_t target_machine)
400+ {
401+ // Read the ELF header and check e_machine matches the target.
402+ // If we can't determine the architecture, accept the file.
403+ if (target_machine == 0 )
404+ return true ;
405+
406+ FILE* f = fopen (path, " rb" );
407+ if (f == NULL )
408+ return false ;
409+
410+ unsigned char hdr[20 ];
411+ if (fread (hdr, 1 , 20 , f) < 20 )
412+ {
413+ fclose (f);
414+ return false ;
415+ }
416+ fclose (f);
417+
418+ // Verify ELF magic.
419+ if (hdr[0 ] != 0x7f || hdr[1 ] != ' E' || hdr[2 ] != ' L' || hdr[3 ] != ' F' )
420+ return false ;
421+
422+ // e_machine is at offset 18, 2 bytes, in the ELF header's native
423+ // byte order. hdr[5] == 1 means little-endian, 2 means big-endian.
424+ uint16_t machine;
425+ if (hdr[5 ] == 1 )
426+ machine = (uint16_t )hdr[18 ] | ((uint16_t )hdr[19 ] << 8 );
427+ else
428+ machine = ((uint16_t )hdr[18 ] << 8 ) | (uint16_t )hdr[19 ];
429+
430+ return machine == target_machine;
431+ }
432+
433+ static const char * find_ponyc_crt_dir (ast_t * program, compile_t * c)
434+ {
435+ uint16_t target_machine = expected_elf_machine (c);
386436 size_t count = program_lib_path_count (program);
387437 char buf[PATH_MAX];
388438
389439 for (size_t i = 0 ; i < count; i++)
390440 {
391441 const char * path = program_lib_path_at (program, i);
392442 snprintf (buf, sizeof (buf), " %s/crtbeginS.o" , path);
393- if (file_exists (buf))
443+ if (file_exists (buf) && elf_matches_target (buf, target_machine) )
394444 return path;
395445 }
396446
@@ -402,27 +452,44 @@ static const char* find_gcc_lib_dir(const char* sysroot,
402452{
403453 // Search for GCC runtime library directory containing libgcc.a.
404454 // Check multiple base paths and pick the highest version.
405- const char * base_patterns[] = {
406- " /usr/lib/gcc" ,
407- NULL , // sysroot-relative patterns filled in below
408- NULL
409- };
455+ //
456+ // Debian/Ubuntu cross-compiler packages install to /usr/lib/gcc-cross/
457+ // rather than /usr/lib/gcc/. Custom GCC cross-compiler builds (e.g. the
458+ // arm/armhf CI containers) install to /usr/local/lib/gcc/.
459+ const char * base_patterns[8 ];
460+ int pattern_count = 0 ;
410461
411462 char sysroot_rel[PATH_MAX];
412- char sysroot_internal[PATH_MAX];
463+ char sysroot_rel_cross[PATH_MAX];
464+ char sysroot_parent_rel[PATH_MAX];
465+ char sysroot_parent_rel_cross[PATH_MAX];
466+
467+ base_patterns[pattern_count++] = " /usr/lib/gcc" ;
468+ base_patterns[pattern_count++] = " /usr/lib/gcc-cross" ;
469+ base_patterns[pattern_count++] = " /usr/local/lib/gcc" ;
470+ base_patterns[pattern_count++] = " /usr/local/lib/gcc-cross" ;
413471
414- // <sysroot>/../lib/gcc
472+ // <sysroot>/../lib/gcc (handles sysroot=/usr/<triple>)
415473 snprintf (sysroot_rel, sizeof (sysroot_rel), " %s/../lib/gcc" , sysroot);
416- base_patterns[1 ] = sysroot_rel;
474+ base_patterns[pattern_count++ ] = sysroot_rel;
417475
418- // <sysroot>/lib/gcc
419- snprintf (sysroot_internal, sizeof (sysroot_internal), " %s/lib/gcc" , sysroot);
420- base_patterns[2 ] = sysroot_internal;
476+ snprintf (sysroot_rel_cross, sizeof (sysroot_rel_cross),
477+ " %s/../lib/gcc-cross" , sysroot);
478+ base_patterns[pattern_count++] = sysroot_rel_cross;
479+
480+ // <sysroot>/../../lib/gcc (handles sysroot=/usr/local/<triple>/libc)
481+ snprintf (sysroot_parent_rel, sizeof (sysroot_parent_rel),
482+ " %s/../../lib/gcc" , sysroot);
483+ base_patterns[pattern_count++] = sysroot_parent_rel;
484+
485+ snprintf (sysroot_parent_rel_cross, sizeof (sysroot_parent_rel_cross),
486+ " %s/../../lib/gcc-cross" , sysroot);
487+ base_patterns[pattern_count++] = sysroot_parent_rel_cross;
421488
422489 const char * best_dir = NULL ;
423490 int best_version = -1 ;
424491
425- for (int p = 0 ; p < 3 ; p++)
492+ for (int p = 0 ; p < pattern_count ; p++)
426493 {
427494 char triple_dir[PATH_MAX];
428495 snprintf (triple_dir, sizeof (triple_dir), " %s/%s" ,
@@ -561,7 +628,7 @@ static bool link_exe_lld_elf(compile_t* c, ast_t* program,
561628 return false ;
562629 }
563630
564- const char * ponyc_crt_dir = find_ponyc_crt_dir (program, c-> opt );
631+ const char * ponyc_crt_dir = find_ponyc_crt_dir (program, c);
565632 if (ponyc_crt_dir == NULL )
566633 {
567634 errorf (errors, NULL ,
@@ -598,6 +665,40 @@ static bool link_exe_lld_elf(compile_t* c, ast_t* program,
598665 args.push_back (" --build-id" );
599666 args.push_back (" --eh-frame-hdr" );
600667
668+ // Pass --sysroot so LLD can resolve absolute paths in linker scripts
669+ // (e.g. libc.so referencing /lib/libc.so.6). However, some cross
670+ // toolchains (Debian gcc-cross packages) generate linker scripts with
671+ // fully-qualified paths that already include the sysroot prefix. LLD
672+ // doesn't fall back to the original path after prepending sysroot
673+ // (unlike GNU ld), so --sysroot would cause double-prepending. Detect
674+ // this by checking whether libc.so contains the sysroot path.
675+ {
676+ bool needs_sysroot = true ;
677+ char libc_so_path[PATH_MAX];
678+ snprintf (libc_so_path, sizeof (libc_so_path), " %s/libc.so" , libc_crt_dir);
679+
680+ FILE* f = fopen (libc_so_path, " r" );
681+ if (f != NULL )
682+ {
683+ char line[1024 ];
684+ while (fgets (line, sizeof (line), f) != NULL )
685+ {
686+ if (strstr (line, sysroot) != NULL )
687+ {
688+ needs_sysroot = false ;
689+ break ;
690+ }
691+ }
692+ fclose (f);
693+ }
694+
695+ if (needs_sysroot)
696+ {
697+ snprintf (buf, sizeof (buf), " --sysroot=%s" , sysroot);
698+ args.push_back (stringtab (buf));
699+ }
700+ }
701+
601702 if (c->opt ->staticbin )
602703 {
603704 args.push_back (" -static" );
@@ -659,6 +760,22 @@ static bool link_exe_lld_elf(compile_t* c, ast_t* program,
659760 {
660761 snprintf (buf, sizeof (buf), " -L%s" , gcc_lib_dir);
661762 args.push_back (stringtab (buf));
763+
764+ // GCC installs shared runtime libraries (libatomic, libgcc_s) in
765+ // <prefix>/<triple>/lib/ while static libraries (libgcc.a) go in
766+ // <prefix>/lib/gcc[-cross]/<triple>/<version>/. Derive the former
767+ // from the latter.
768+ char gcc_target_lib[PATH_MAX];
769+ snprintf (gcc_target_lib, sizeof (gcc_target_lib),
770+ " %s/../../../../%s/lib" , gcc_lib_dir, sys_triple);
771+
772+ struct stat gcc_target_stat;
773+ if (stat (gcc_target_lib, &gcc_target_stat) == 0
774+ && S_ISDIR (gcc_target_stat.st_mode ))
775+ {
776+ snprintf (buf, sizeof (buf), " -L%s" , gcc_target_lib);
777+ args.push_back (stringtab (buf));
778+ }
662779 }
663780
664781 // Add ponyc lib paths and user lib paths.
@@ -688,13 +805,26 @@ static bool link_exe_lld_elf(compile_t* c, ast_t* program,
688805 }
689806 }
690807
691- // Pony runtime.
808+ // Pony runtime. Use the full path from ponyc_crt_dir to ensure we
809+ // pick the target-architecture library, not a native-arch copy that
810+ // might appear earlier in the -L search path.
692811 if (!c->opt ->runtimebc )
693812 {
694- if (c->opt ->staticbin )
695- args.push_back (" -lponyrt" );
813+ const char * rt_name = c->opt ->staticbin ? " libponyrt.a"
814+ : (c->opt ->pic ? " libponyrt-pic.a" : " libponyrt.a" );
815+
816+ snprintf (buf, sizeof (buf), " %s/%s" , ponyc_crt_dir, rt_name);
817+ if (file_exists (buf))
818+ {
819+ args.push_back (stringtab (buf));
820+ }
696821 else
697- args.push_back (c->opt ->pic ? " -lponyrt-pic" : " -lponyrt" );
822+ {
823+ if (c->opt ->staticbin )
824+ args.push_back (" -lponyrt" );
825+ else
826+ args.push_back (c->opt ->pic ? " -lponyrt-pic" : " -lponyrt" );
827+ }
698828 }
699829
700830 args.push_back (" -lpthread" );
0 commit comments