Announcement

Collapse
No announcement yet.

LoadLibrary: Support For Loading Windows DLLs On Linux

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #71
    Originally posted by Weasel View Post
    You're the one attempting to move goal posts, idiot. We were talking about object files (i.e. COFF) and ELF and why they have global symbols. C++ has nothing to do with PE, that's the linker's problem. This was about object files.
    There is a problem.

    Originally posted by Weasel View Post
    Let's recap.

    PE doesn't have global symbols, it cannot store them.
    This is wrong. UEFI PE does store global symbols like it or not. Windows PE does not. If PE stores global symbols or not is choice of the loader like it or not. And don't give me this is broke PE Microsoft signed off on it.

    Originally posted by Weasel View Post
    ELF can because it's "one format" for both a DLL and an object file. So it sucks as a dynamic link library.
    This is wrong. This is forgetting static and dynamic tables exist inside ELF.

    Originally posted by Weasel View Post
    Object files must be able to store global symbols, because that's how C/C++ work. At least with portable source code.
    That only effects the rules over the static tables as in the tables for static linking. You find static tables in ELF with STT_FILE filled in. One of the static programs of java programs for ELF platforms did exploit this. So Coff cannot store the information you need to perform particular static links because its limited to C/C++ stuff. ELF is not. So this line you just wrote is wrong that object files must store global symbols.

    Really this with C and C++ is so wrong its not funny that you have to store global symbols. If C/C++ has to work always by global symbols how can you use it with PE format.



    C and C++ compilers are allowed to add extra information as the standard don't forbid extending. The two foo in that lwn.net are appear in the ELF static link table with extra information on linking handling. Just because format stores extra information like the STT_FILE in static linking so you can back trace what object a function comes from does not mean the linker cannot do a global resolve. So no object formats don't have to be able to store global symbols for C or C++ to work. The linker has to be able to process global symbols to fill in the blanks for C standard to work. Same way coff to PE link process fills in the blanks but this can in fact been done at the object static link and is with different ELF linkers.


    Originally posted by Weasel View Post
    COFF and ELF can store global symbols, which is good for object files, not for a dynamic library.
    UEFI PE can as well. So on the point of global symbols base format PE/ELF/COFF no difference. Its a question if the dynamic loader/linker of the format will accept and process global symbols. COFF has the limitation it cannot be used in environments lacking global symbols where both PE and ELF can be used without global symbols.

    Like it or not PE/COFF if you go to the base specifications has the problem and always has had.

    Weasel how much did you get right in your recap basically nothing.

    Comment


    • #72
      Originally posted by oiaohm View Post
      Really this with C and C++ is so wrong its not funny that you have to store global symbols. If C/C++ has to work always by global symbols how can you use it with PE format.
      .def files.

      You can have these functions/symbols in C++:

      Code:
      void magicFunctionName();
      void anotherFunctionName();
      and have both map to the name "function" on different DLLs using .def file.

      The names "magicFunctionName" and "anotherFunctionName" will never appear in the final PE. They will only appear temporarily during building in COFF object files. And you can make them as long as you want, they're only for building and not for release.

      Comment


      • #73
        Originally posted by Weasel View Post
        .def files.

        You can have these functions/symbols in C++:

        Code:
        void magicFunctionName();
        void anotherFunctionName();
        and have both map to the name "function" on different DLLs using .def file.

        The names "magicFunctionName" and "anotherFunctionName" will never appear in the final PE. They will only appear temporarily during building in COFF object files. And you can make them as long as you want, they're only for building and not for release.
        This where you have trouble your example did not cover the case I pointed to.


        Code:
        __attribute__ ((target ("sse4.2")))
        int foo(){
           // foo version for SSE4.2
           return 1;
        }
        
        __attribute__ ((target ("arch=atom")))
        int foo(){
           // foo version for the Intel Atom processor
           return 2;
        }
        
        int main() {
          int (*p)() = &foo; assert((*p)() == foo());
          return 0;
        }
        C standard does not define if you can declare function more than once per object file. Its left as undefined behaviour for the compiler to decide if it support it or not. This above automatically comes a ifunc on ELF platforms. With .symver I can put multi functions named the same in the one library under ELF.

        Also you are using .def instead of C/C++ extension.


        This fun thing exists now
        Code:
        __attribute__ ((__symver__ ("foo@VERS_1"))) void foo_v1() {
        //some code
        }
        
        __attribute__ ((__symver__ ("foo@VERS_2"))) void foo_v2(){
        //somecode
        }
        Try doing this in your PE. Both of those are exported as symbol foo.

        For the reverse inside gcc.


        This is stuff that has been recently fixed up so far. At this stage you cannot name both functions foo on the C side like you can do with target as that would require have means to put __symver__ value on a function usage not just on function define and declares(not impossible in future). The reality here is C standard does not say you have to be restricted to to 1 version of a function per source file or that every function has to be named uniquely..

        So one of the limitations of PE/COFF is only 1 version of a symbol per object file/dll.

        C and C++ undefined behaviour areas are huge.

        Telling Linux users to use PE instead of ELF you are saying give up all this useful stuff and not be able to push C standard undefined areas to the max for optimisations and other things.

        The idea that C and C++ require global symbol resolve is bogus. Using C and C++ with global symbol resolve means platform compiler don't have to implement platform extensions to C/C++ and you can get away with using COFF as your object format instead of something more capable like ELF.

        Yes look at the gcc world __symver__ with PE you should be able todo like .

        Code:
        __attribute__ ((__dllref__ ("[email protected]"))) void foo1();
        __attribute__ ((__dllref__ ("[email protected]"))) void foo2();
        But you cannot do this into a COFF object because it does not have the tables to store that information so Microsoft has never created anything like this.

        PE format ties you hands in many ways. Fixing the ELF loader would allow keeping a lot of useful features.

        Notice something important here Weasel on the ELF platforms we have a lot of control from the C/C++ source files you don't have on PE platforms because the compiler has been able to be extended to store extra information in the ELF format tables. Of course what a C/C++ compiler on ELF platforms can store in the ELF format from a C/C++ file is always extending.

        Comment


        • #74
          As I said this is not something that should be done in C/C++, but at linker level. I never said you can't do it for ELF, but that it needs compiler extensions, and you literally just proved that, so idk what you're trying to argue about.

          The linker has nothing to do with C/C++. You can link object files created in other languages or even assembly and then map their symbols to whatever names. On the other hand your way requires these extensions into each and every language that supports it. The __asm__ thing in particular won't even work if you use a different assembler than those compatible with GNU AS.

          Comment


          • #75
            Originally posted by Weasel View Post
            As I said this is not something that should be done in C/C++, but at linker level.
            But is that even right today heck as it been absolute right for years answer is no. Basically you are ignoring the existence of loadlibrary under windows and dlopen under posix systems and how these functions are used.

            If people are going to be loading libraries using C and C++ code you need to make the process as clean and tidy as possible for what they are trying todo. Both loadlibrary and dlopen ends up requiring programmer to write more lines of code to achieve the same thing as complier extention to the C language could do. Please note loadlibrary and dlopen are not part of the C or C++ specification. There is a lot of code out there that is not portable and is problematic so should be solved by extending the language one way or the other..


            Originally posted by Weasel View Post
            The linker has nothing to do with C/C++. .
            This might be true for Microsoft compilers but its not true for gcc. There is such a thing as link time optimisation and link time static analyzation so when you get to link stage you are not just linking objects together any more.

            Static analyzation is where things get very interesting where what you say do at the linking stage starts making less sense.


            Code:
            __attribute__ ((__symver__ ("malloc@VERS_1"))) void *foo_malloc(size_t size)
            __attribute__ ((__symver__ ("free@VERS_1"))) void foo_free(void *ptr);
            
            int main () {
            char * junk;
            junk=(char *) foo_malloc(10);
            foo_free(junk);
            foo_free(junk);
            }
            This if you use the right VERS_1 for a glibc version with ELF gcc with static analyzation turned on will in fact throw a double free error when you build the object. Because it worked out that foo_malloc and foo_free are in fact free and malloc. It can at time nicely throw a error if its not a double free and the free and malloc are different versions. This would be nice at times if this happened with different dll names/sonames right.

            Originally posted by Weasel View Post
            You can link object files created in other languages or even assembly and then map their symbols to whatever names.
            Generally most programs are done in a single programming language why using multi languages increased you defect rate due to the languages having different memory management and other things so the idea that we need link objects created by different languages is mostly bogus these days and a path to errors.

            Late mapping in the linking stage means the static analyzation at the object stage is lacking key information to make correct erorrs/warnings at that point. Yes weasel effective static analyzation in compilers is needing early mapping not late. When the idea of object/linker was created we were not doing static analyzation in compliers so were not needing this information early. Yes COFF format was designed before people started serous-ally doing static analyzation so was design without the means to early map. ELF format was in fact first designed where people started doing static analyzation in compilers so this is why there is not the split between object and executable format and has the ability to early map.

            ELF design is not a random choice. Weasel you have been attempt to argue against something that was totally done intentionally when ELF was designed and this intentional design is coming more required.

            Originally posted by Weasel View Post
            On the other hand your way requires these extensions into each and every language that supports it. The __asm__ thing in particular won't even work if you use a different assembler than those compatible with GNU AS.
            .symver statements is in fact supported by all assmblers that produce ELF even when all the other assembler codes don't match GNU AS so that GNU AS arguement is kind of wrong. Something things have kind of come defacto standards in the ELF world because they work.

            Like it or not extensions to C and C++ are required to make compilers be able to return static analyzation detected code defects sooner. There are many langauges that you need to extend for effective static analyzation. Basically complaining about needing to extend the language says you don't want effective early static analyzation that is the choice you are in fact making Weasel.

            Weasel you started with the solid idea that elf design is wrong and totally missed why ELF is designed the way it is and why that design is required. This is why I say fix ELF and PE is not a option without major changes. ELF design allows it to be fixed in a transition without really breaking anything in the process.
            Last edited by oiaohm; 28 March 2020, 06:20 PM.

            Comment

            Working...
            X