<!DOCTYPE html>
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi,</p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">I suspect that my first message was blocked
            because I attached ODT document. Please ignore duplicate if
            it show up.</span></span></span></p>
    <p>I mentioned about this issue some time ago in the topic about
      PasFLTK bindings which I made. I decided to make dedicated thread
      because it seems to be interesting.</p>
    <p>So. I'm developing PasFLTK bindings for CFLTK which is flatten C
      binding for major FLTK UI framework written in C++. PasFLTK has
      two modes, shared library which work perfectly fine and
      experimental static linking.</p>
    <p>Static linking has issues which I'm <span class="HwtZe" lang="en"><span
          class="jCAhz ChMk0b"><span class="ryNqvb">consistently</span></span></span> fixing.
      Major problem is that C++ classes are not initialized in proper
      way. Problem is not a matter of "Static Initialization Order
      Fiasco" because CFLTK/FLTK is designed to be static linking for
      default (and that is how other language bindings are using it).
      Problem is how FPC LD linker prepare "startup" routines. For
      example:</p>
    <p>Class Fl_File_Chooser2.cxx has this public variable:</p>
    <p>const char      *Fl_File_Chooser::filesystems_label =
      Fl::system_driver()->filesystems_label();</p>
    <p>System_driver is not initialized yet so filesystems_label become
      null which result with access violations. Since I'm linux user I
      started from this platform, working on this with Claude AI (which
      amazed me how deeply he can analyze binaries on low level). On
      linux, fix was small and easy (for Claude, not for me of course).
      LD linker prepare wrong init structure and doesn't call the
      __init_array_start in linux ELF standard. So patch looks like
      that:<br>
      <br>
    </p>
    <p>type<br>
        TCtorProc = procedure(); cdecl;<br>
        PCtorProc = ^TCtorProc;<br>
      <br>
      var<br>
        __init_array_start: Byte; external name '__init_array_start';<br>
        __init_array_end: Byte; external name '__init_array_end';<br>
      <br>
      procedure RunCppGlobalConstructorsLinux;<br>
      var<br>
        p, pend: PCtorProc;<br>
      begin<br>
        p := PCtorProc(@__init_array_start);<br>
        pend := PCtorProc(@__init_array_end);<br>
        while p < pend do<br>
        begin<br>
          if Assigned(p^) then<br>
            p^();<br>
          Inc(p);<br>
        end;<br>
      end; <br>
      <br>
      That small piece of code fixed everything and static linking work
      like a charm on linux. I have project (which I publish soon)
      totally written as static linking and didn't notice any new issues
      so far.</p>
    <p>Now windows version. Here complication start. First, build-in FPC
      linker is useless and throw error:</p>
    <p>Error: Failed reading coff file, invalid section index while
      reading
      C:\Users\vboxuser\Documents\CFLTKlibs\libcfltk.a(cfl_window.cpp.obj)<br>
      <br>
      I had to use -Xe flag which switch to external ld.exe linker. But
      then I had DWARF errors because LD support only up to 4 version
      and my MinGW toolchain (MSYS2 on windows) is using ver. 5. I had
      to call `strip --strip-debug` on all *.a files (including some
      MinGW - e.g libstd++.a).</p>
    <p>Now, when binding are compiling fine, I fall to the same problem
      with initialization as on linux. I spent few evenings with Claude
      on this. We compared objdump -h and extracted objects on exactly
      the same demos written line by line one using C (CFLTK) and second
      Free Pascal. Since linux use ELF we get __init_array_start, on
      windows PE - it looks harder. LD.exe <span class="HwtZe" lang="en"><span
          class="jCAhz ChMk0b"><span class="ryNqvb">delivered with FPC
            is quite old and doesn't use modern standard. Demo written
            in C and linked by LD from toolchain has correct .ctors and
            __CTOR_LIST__ which FPC ld.exe is missing (in fact, filling
            it incorrectly). Tried using -FD"C:\msys64\mingw64\bin"
            which load ld.exe from MinGW toolchain but this result with
            dozens errors:</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">C:\msys64\mingw64\bin\ld.exe:
            C:\programowanie\lazarus\fpc\3.2.2\units\x86_64-win64\rtl\sysutils.o:
            illegal relocation type 0 at address 0<br>
            C:\msys64\mingw64\bin\ld.exe:
            C:\programowanie\lazarus\fpc\3.2.2\units\x86_64-win64\rtl\math.o:
            illegal relocation type 0 at address 0</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Claude also compared rust bindings for CFLTK
            because it also use static linking. They had also problems
            and are stick to the specific toolchain. But there problem
            was easier to fix because Rust linker correctly linking
            crt2.o and has own guardians rsbegin.o and rsend.o (</span></span></span><span
        class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">equivalent of </span></span></span>crtbegin.o
      and crtend.o) which are missing in FPC ld linker.</p>
    <p>Finally I get it working with Claude but this require reorganize
      *.a and C++ objects with --globalize-symbol and this solution is
      not acceptable for me because it require <span class="HwtZe"
        lang="en"><span class="jCAhz ChMk0b"><span class="ryNqvb">engagement
            everytime when something changed in CFLT/FLTK source or even
            in MinGW.</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">I'll be not writting anymore and just attach
            summary of our work which I asked Claude to write in short.
            It has more technical details. To sum up. Is there any plans
            to upgrade LD linker or exists any alpha / beta of upcoming
            release? </span></span></span><span class="HwtZe" lang="en"><span
          class="jCAhz ChMk0b"><span class="ryNqvb">The difference
            between FPC ld and GCC ld is almost 10 years. </span></span></span><span
        class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">I read somewhere that FPC is not designed to
            link C++ (only C) but as we can see, it could be just small
            step to make it possible and that open huge door. </span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Below is Claude's summary.</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Regards, Dibo.</span></span></span></p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb">Environment:<br>
            <br>
                Free Pascal Compiler 3.2.2, Windows target x86_64-win64<br>
            <br>
                Bundled linker:
            C:\programowanie\lazarus\fpc\3.2.2\bin\x86_64-win64\ld.exe —
            GNU ld (GNU Binutils) 2.28<br>
            <br>
                Comparison linker: ld.exe from MSYS2
            mingw-w64-x86_64-binutils package, located at
            C:\msys64\mingw64\bin\ld.exe — GNU ld (GNU Binutils) 2.46.1<br>
            <br>
                GCC/G++ used to build FLTK, CFLTK, and the comparison
            C++ demo: 16.1.0 (MSYS2 mingw-w64-x86_64-gcc, reported as
            "GCC 16.1.0"<br>
            <br>
                FLTK version: 1.4.5, CFLTK version: 1.5.23<br>
            <br>
            Root cause identified: FPC 3.2.2's bundled ld.exe fails to
            correctly merge .ctors input sections (containing C++ global
            constructor pointers) from object files compiled by a modern
            GCC (16.1.0, MinGW-w64/MSYS2) into the final __CTOR_LIST__
            array — even though the linker script (identical
            KEEP(*(.ctors)) rule, confirmed via ld.exe --verbose on both
            linkers) is present in both the old bundled ld.exe and a
            current MSYS2 ld.exe.<br>
            <br>
            Evidence:<br>
            <br>
                A raw hex dump of __CTOR_LIST__ in an FPC-linked
            executable (with 10 real global constructors from a
            statically-linked FLTK/CFLTK library present and confirmed
            via nm) shows: sentinel (-1) immediately followed by
            terminator (0) — zero constructor pointers, despite the
            constructor functions (_GLOBAL__sub_I_*) physically existing
            in the binary.<br>
            <br>
                The same source compiled and linked natively with
            g++.exe/current MSYS2 ld.exe produces a fully populated
            __CTOR_LIST__ with all 10 pointers correctly resolved to the
            matching _GLOBAL__sub_I_* addresses.<br>
            <br>
                Attempting to relink the FPC-built binary with the
            current MSYS2 ld.exe (via -FD<path>) fails with
            illegal relocation type 0 / invalid section index errors on
            FPC's own RTL object files (sysutils.o, math.o) — indicating
            FPC's internal object emitter and modern binutils have
            diverged in mutually incompatible ways. rtl\sysutils.o:
            illegal relocation type 0 at address 0 etc<br>
            <br>
                The input .o files from the affected FLTK library use
            COMDAT sections (LINK_ONCE_DISCARD) extensively (confirmed
            via objdump -h), which may be related to how the old ld.exe
            mishandles their .ctors content during merging — this is
            hypothesis<br>
            <br>
                Consequently, statically linking modern C++ libraries
            (FLTK/CFLTK, built with current MinGW-w64/GCC) into an
            FPC/Lazarus Windows executable silently drops all global C++
            constructors, causing use of uninitialized static objects
            downstream (observed as intermittent access violations
            depending on which code paths touch affected statics).<br>
            <br>
            Workaround currently used: manually enumerating
            _GLOBAL__sub_I_* symbols via nm on the linked (even if
            crashing) executable, globalizing their linkage scope via
            objcopy --globalize-symbol (they are emitted as local/t
            symbols), and generating a small Pascal unit that calls them
            all explicitly at program startup. This resolves some but
            not all downstream issues, suggesting missing constructor
            invocation is necessary but possibly not sufficient — full
            mainCRTStartup context (TLS/locale/guard-variable state) may
            also matter for some lazily-initialized C++ singletons. -
            this is last hypothesis<br>
            <br>
            Question for the list: Is there a newer/beta ld.exe (or plan
            to update the bundled binutils) for the Windows FPC
            toolchain that correctly handles .ctors/COMDAT sections as
            emitted by current GCC, without breaking compatibility with
            FPC's own object file emitter?</span></span></span></p>
    <p><br>
    </p>
    <p><span class="HwtZe" lang="en"><span class="jCAhz ChMk0b"><span
            class="ryNqvb"><br>
          </span></span></span></p>
  </body>
</html>