Announcement

Collapse
No announcement yet.

Fedora 29 Might Make Change To Eliminate Unnecessary Linking

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

  • coder
    replied
    Originally posted by Weasel View Post
    And the other argument was about destructors being totally fine in C++ code as a design, and "free functions" being the equivalent on C, yet you talk as if those free functions (e.g. "DestroyObjectFoo") are an exception and not proper design and you should just use free() directly WTF.
    No, what I said is that it's natural for them to do cleanup of the object and free its memory. That's what I've always done, in C.

    Originally posted by Weasel View Post
    Using free() directly is the equivalent of not having a destructor at all.
    No, free() is the second stage of cleaning up an object. The first stage is deallocating the resources held by the object. Destructors perform only the first stage.

    Leave a comment:


  • Weasel
    replied
    Originally posted by F.Ultra View Post
    Why are you assuming such stupid things? From your reasonings I take it that you have limited experience with programming for and on Linux systems. Otherwise you would have known that when people start to try out clang on say debian/Ubuntu (apt install clang) they now have exactly the situation that you described as not working, i.e every single library that they link with is compiled with GCC while their own code is compiled with Clang.

    I don't even understand why you think that this would not work, both are linking with the exact same libc so malloc() and free() work on the exact same heap. Just for kicks I did try this, created a small .so that implemented a basic strdup() like function, compiled it with GCC on my home computer and then I launched a new Ubuntu instance in VirtualBox where I installed clang and scp:ed the .so over to that instance, made a small test app that linked with this .so and allocated one million strings in an array and free:d them all and not a single memory error (and everyone that have ever worked with both Linux and Windows knows that glibc catches far more memory errors than Windows ever does, e.g the memory allocator in glibc contains much more checks by default).
    Well, I was talking about libstdc++ not libc...

    Originally posted by F.Ultra View Post
    And who in their right mind would write code like that? Is it common among Windows devlopers to write that bad code? Any way thanks for demonstrating to people why it's important for your code quality to compile on different systems to find faults in your code.

    Before you go all "Windows Master Race" here you might think about exactly what type of developer it is that adds functionality for a piece of software to work on Windows (a small hint is that it's usually not a Linux dev).
    No, you don't get it. I never said you have to write code like that. But changing it from a function to a macro changes the *behavior* of the source code during compilation, without #ifs. In this particular case it's not a problem, but it can be when there's much more macro pollution.

    Why do you think macros are so discouraged in C++ (less so in C, but still)? They pollute all of the namespaces. In C++ they're much worse since C++ has way more namespaces, even custom namespaces. But even C has namespaces, like for structs, functions, local vars, etc.

    You know there is also a reason that the Linux Kernel hates "typedef struct" stuff and prefers to write "struct structname" all over the place, and this is one of the reasons, besides making it clear it's a struct.

    Originally posted by F.Ultra View Post
    Since we never ever had that kind of discussion I have to assume that you quoted me but made an answer to another person in this thread?

    Anyway, you do realise that ELF is older than both PE and Mach-O right? When Microsoft developed PE and Next developed Mach-O they decided to include two-level namespaces for imports. In traditional Unix and Linux this have as of yet not been seen as a big enough problem due to how software is distributed on e.g Linux and BSD.

    At some point you might discover that different systems work differently where different is not just "bad" or "good", if you however keep on treating Linux/BSD as just another version of Windows you are going to stumble upon trouble.

    Also I don't really get why you keep on spewing insults like "retarded" when systems are not designed exactly how you need them to be on a Windows system.
    I don't know, I forgot who is who, sorry

    Ok, ELF might be older, but that doesn't really justify fanboys defending it (especially pal666). Sure, it may be *excused* due to its age, but IMO after so long, it should have been fixed. Like, force people to use symbol versioning or something, since it already exists and solves this problem, but people just don't use it (except few libraries like glibc which do).

    Anyway even if it's excused for being old, it still makes no sense for anyone to defend ELF's inferiority compared to Mach-O or DLLs.

    Also, I don't understand why people think that the DLL features are "Windows specific". I mean the PE format (which is what DLLs actually are) is even used in UEFI, come on.

    I did talk about Windows but that's because people kept coming up with stuff like "but DLLs provide their own hell <insert nonsense here>". I mean DLLs are *not* perfect, but ELF has nothing better than them. Sure, DLLs also suffer from many things, but you know what? ELF also suffers from the same things that DLL does. DLLs just have *less* problems than ELF, not zero. So ofc I had to clarify that they were speaking nonsense.

    But DLLs are not Windows specific.

    Originally posted by F.Ultra View Post
    AFAIK the Windows loader does not go around and replace the address of each and every symbol, instead it creates a Import Address Table and then instead of performing a "call strdup" it does a "call imp_strdup" i.e a thump, and the loader simply changes the address in the IAT to the real address of the function during loading. This way it does not have to go over GiB of code just to perform relocation.

    So technically there is nothing that prevents MS from switching the base address of the IAT for the C runtime when you call a function in a DLL and switch it back when the call returns. Note that I'm not saying that this is how they implemented this (I have no knowledge of how the MS loader works since I've never been interested in delving into it), just that it can be done this way.
    Yeah, that's what I said, but maybe i worded it poorly.

    "Technically" of course it can replace the IAT of a foreign library (we're talking about a C runtime modifying the IAT of a *different* C runtime loaded in memory at a different address here), but that is like malware behavior, seriously doubt it would do that.

    Not to mention the IAT is read-only by default (the loader removes protection while writing to it, then sets it back to read-only), it would have to be some seriously convoluted code to do that... and on a different library. (it would have to be aware of it, on purpose)

    Leave a comment:


  • F.Ultra
    replied
    Originally posted by Weasel View Post
    But there's no context, man. I'll try to illustrate what *really* happens when you use a callback.

    When you call a function, in CPU instructions, you specify a destination address. A RAM address, because code lives in RAM, just like data. It's made up of bytes and so on. Then, the call pushes the return address (the code address after the call instruction) onto the stack and jumps to that address called. Upon a return instruction, it pops the return from the stack and jumps there, effectively "continuing" after the call instruction.

    When you implement a callback (note: I'm talking about IMPLEMENTING a callback in code) you simply create a normal function, like this:
    Code:
    void my_callback()
    {
    // do the strdup thing here, ofc omitted for simplicity
    }
    This function exists in code like any other function. It exists in YOUR code as a sequence of instructions. There's no "switch" happening, it's a simple, normal function. Heck, you can even CALL it from your own code and all it will do will be a simple CALL instruction (unless it gets inlined).

    So for now I'm ignoring the library. Let's look at what the callback does:
    Code:
    ; some assembly code here
    call strdup
    ; more assembly code
    ret
    It's a simple normal function, right? For now we have no library, just this function. When your module gets loaded, this function is not treated any different. So it simply places strdup's address into the import table, just like any other function. This will be your strdup@static (in this case), which matches that of free@static. Remember, no library was loaded yet, except the standard library. So now there's no conflict because we didn't load another runtime, we agree so far.

    Now Windows loads the other library, which loads the other runtime. Your function and strdup DO NOT change, they've already been fixed and imported. Your function is "loaded" already and exists the way it was when it got loaded.

    When you pass the callback to the new library, you simply give its address to the library. In this case you give the address of "my_callback" (32-bit or 64-bit data) to the library's parameter that takes it (a pointer). When you call this library and pass it the callback, all you do is:
    Code:
    call library_func
    where library_func is imported by the loader. There's no switch yet.

    Later, when the new library (using the new runtime) decides to call your callback, all it does is:
    Code:
    call *ptr
    where "ptr" holds your "my_callback" address.

    That's... it.

    Literally.

    There's no switch. The strdup@static shouldn't even be aware it got called from a callback: all it knows (via return address) is that it was called from my_callback, which is a normal function. In fact, you can even call my_callback from YOUR own code, and the behavior is completely identical. Even the return address will be identical (it's my_callback's) and strdup won't know the difference.

    This is why to me it is literally impossible to conflict here. Conflicts happen during load time -- when the loader (DLL or ELF) replaces symbols with their actual addresses. The problem with ELF is that a symbol may be used by more than 1 library, that's literally its only problem. In this case it will conflict during LOAD (but the crash will happen later when it's called of course).
    AFAIK the Windows loader does not go around and replace the address of each and every symbol, instead it creates a Import Address Table and then instead of performing a "call strdup" it does a "call imp_strdup" i.e a thump, and the loader simply changes the address in the IAT to the real address of the function during loading. This way it does not have to go over GiB of code just to perform relocation.

    So technically there is nothing that prevents MS from switching the base address of the IAT for the C runtime when you call a function in a DLL and switch it back when the call returns. Note that I'm not saying that this is how they implemented this (I have no knowledge of how the MS loader works since I've never been interested in delving into it), just that it can be done this way.

    Leave a comment:


  • F.Ultra
    replied
    Originally posted by Weasel View Post
    Oh, so basically they solve the same problem as DLLs.

    Which means Linux's ELF is the only one that's retarded and you still "didn't understand" what I was talking about...
    Since we never ever had that kind of discussion I have to assume that you quoted me but made an answer to another person in this thread?

    Anyway, you do realise that ELF is older than both PE and Mach-O right? When Microsoft developed PE and Next developed Mach-O they decided to include two-level namespaces for imports. In traditional Unix and Linux this have as of yet not been seen as a big enough problem due to how software is distributed on e.g Linux and BSD.

    At some point you might discover that different systems work differently where different is not just "bad" or "good", if you however keep on treating Linux/BSD as just another version of Windows you are going to stumble upon trouble.

    Also I don't really get why you keep on spewing insults like "retarded" when systems are not designed exactly how you need them to be on a Windows system.
    Last edited by F.Ultra; 07 July 2018, 11:08 AM.

    Leave a comment:


  • F.Ultra
    replied
    I planned to go to work after hitting the gym yesterday to test the Windows callback problem but I got called home by my teenage daughter who came home from her boyfriend and needed to get in our house so I had to drive home and unlock the door. I have one more week of vacation so I don't know yet if I will try to sneak away again to the office or if I will wait until I'm back from my vacation.

    In any way I noticed that I had missed to comment on this:

    Originally posted by Weasel View Post
    No, having a library-specific free() function is the best way to design it because 1) it respects the language (your "unix way" violates ODR, see my previous post), and 2) it allows the library to expand its internal representation without breaking the app, transparently.

    You can get a potential crash on Unix because it violates the C/C++ language rules. Just because it doesn't crash in YOUR case doesn't mean it's correct code.

    For example, if you make an app with Clang and link a library built with GCC and do this insane thing, it will crash. That's beyond absurd, it's pathetic and stinks of trash code.
    Why are you assuming such stupid things? From your reasonings I take it that you have limited experience with programming for and on Linux systems. Otherwise you would have known that when people start to try out clang on say debian/Ubuntu (apt install clang) they now have exactly the situation that you described as not working, i.e every single library that they link with is compiled with GCC while their own code is compiled with Clang.

    I don't even understand why you think that this would not work, both are linking with the exact same libc so malloc() and free() work on the exact same heap. Just for kicks I did try this, created a small .so that implemented a basic strdup() like function, compiled it with GCC on my home computer and then I launched a new Ubuntu instance in VirtualBox where I installed clang and scp:ed the .so over to that instance, made a small test app that linked with this .so and allocated one million strings in an array and free:d them all and not a single memory error (and everyone that have ever worked with both Linux and Windows knows that glibc catches far more memory errors than Windows ever does, e.g the memory allocator in glibc contains much more checks by default).

    Originally posted by Weasel View Post
    Also thanks for giving some examples, those libraries deserve to be in the "hall of shame". Your ne_free is even worse since it's a macro which is substantially different behavior than a function, so code relying on that shameful library won't even be guaranteed the same behavior.

    This code:
    Code:
    int foobar()
    {
    int ne_free; unsigned int free = 42;
    /* ... */
    }
    Will fail to compile on code that uses that stupid library on Unix but not on Windows, isn't that just great design?

    Very "solid" library design. I can imagine they put so much thought into it /sarcasm

    Shining standard of code there. Of course, Linux libs never cease to amaze me at their poor quality, so whatever.
    And who in their right mind would write code like that? Is it common among Windows devlopers to write that bad code? Any way thanks for demonstrating to people why it's important for your code quality to compile on different systems to find faults in your code.

    Before you go all "Windows Master Race" here you might think about exactly what type of developer it is that adds functionality for a piece of software to work on Windows (a small hint is that it's usually not a Linux dev).

    Leave a comment:


  • Weasel
    replied
    Originally posted by coder View Post
    Sorry, but I can't agree that it's only and always a virtue. The same post you cite notes a number of downsides.
    All the downsides to it are literally due to breaking backwards compatibility because it was public in the first place. If it wasn't public, then none of it would be an issue, as everything would have been designed sanely from day 1. So no drawbacks.


    And the other argument was about destructors being totally fine in C++ code as a design, and "free functions" being the equivalent on C, yet you talk as if those free functions (e.g. "DestroyObjectFoo") are an exception and not proper design and you should just use free() directly WTF. Using free() directly is the equivalent of not having a destructor at all. Nobody encourages that for C++ so why say C is any different makes no sense.

    There's literally no difference. Maybe you were arguing about something else, but that is your fault.
    Last edited by Weasel; 07 July 2018, 09:38 AM.

    Leave a comment:


  • Weasel
    replied
    Originally posted by F.Ultra View Post

    The two-level namespace in Mach-o (the name is Mach-o and not Macho-o) means that each imported symbol have their corresponding library defined.

    Lets say that we have one process A and three shared libraries B, C and D.

    Process A links with B to use function1() and with C to use function2().
    Library C links with D to use function1() in it's function2().

    We now have two different functions named function1() (one from B and one from D).

    In a non-versioned ELF situation we end up with function1() from B being used both when it's called from A and when it's called from function2() in C.

    On Mach-o however since each exported symbol have their respective library name attached function1() from B will be used when called from A and function1() from D will be used when called from function2() in C.
    Oh, so basically they solve the same problem as DLLs.

    Which means Linux's ELF is the only one that's retarded and you still "didn't understand" what I was talking about...

    Originally posted by coder View Post
    I'm not a fanboy; just calling out your small-minded, fascist assertions about library design for what they are.
    Ah, now the classic invocation of Godwin's law when losing the argument.

    Have you ever considered that maybe, just maybe, instead of everyone else (who follows proper coding etiquette, I already told you links and where to ask if you *really* wanted to, so no excuses) being fascist, maybe it's just you?

    Fanatical about everything Linux to the point where you even tolerate and consider good to violate the C/C++ language's rules. Yikes.

    Originally posted by coder View Post
    Wine is so much more than just a loader. If you're exclusively using Wine, you're really trying not to use Linux, not least because it just gets in the way of most of Linux' native features and capabilities, not to mention the userland ecosystem for which you have such seething contempt.
    And Linux is just the kernel so it's also "much more" than just the stupid ELF...? Dude, just stop grasping for straws, it's embarassing.

    Wine gets in the way of "Linux' native features and capabilities", ok, such as? Any such capability I should give a shit about? Tell me.

    (of course, most command line tools on Linux are fine that just link to libc or some utility library -- I never complained about those, but more complex / portable apps with GUIs, not for system administration)

    Also, you can use the Linux kernel (syscalls) from a Wine app, you can even use the virtual filesystems (/sys and /proc) to interface with the kernel (just use the path \\?\unix\sys\... for example). Yes, you can even do system administration with Wine apps, if you really wanted to (but it's not much point since system administration apps aren't portable anyway and they're just fine on Linux' userland). Indeed so many features missing...

    Originally posted by coder View Post
    It's like 98% Linux and Linux-centric opensource. Reasonable people will agree that coming on here and shitposting about Linux is trolling behavior.
    Oh you must be one of those who need their "safe space" so they retreat to a place where they can't stand any valid criticism. Sorry to say but this forum is not that place, maybe consider making your own blog, there you can post and allow what you want (aka only people who agree with your ideologies).
    Last edited by Weasel; 07 July 2018, 09:35 AM.

    Leave a comment:


  • coder
    replied
    Originally posted by Weasel View Post
    Show me disassembled C++ destructor code and then a "normal" function call and let's look at the difference (ofc destructor would have a mangled name based on its class and an implicit parameter for the object). If I show you any, you'll say I compiled the wrong code, so go show it champ.
    For a point you've missed, you're sure unwilling to let it go. If you care, try reading back a few posts. I'm not going to repeat my point, only for you to miss it yet again.

    Originally posted by Weasel View Post
    Another retarded Unix/Linux thing is default public visibility. Microsoft got it right with default private visibility, and I have to admit facts when I see them.
    Sorry, but I can't agree that it's only and always a virtue. The same post you cite notes a number of downsides.

    Leave a comment:


  • coder
    replied
    Originally posted by Weasel View Post
    Spreading facts and calling bullshit for what it is, so that viewers are not drawn by fanboys' logic and false claims. I mean it's public, so obviously it's for viewers to read.
    I'm not a fanboy; just calling out your small-minded, fascist assertions about library design for what they are.

    Originally posted by Weasel View Post
    This is the kind of nonsense I'm talking about. I said I don't use ELF unless I have to, and most certainly do not develop for ELF because it's archaic and retarded. Linux can use DLLs, it's called Wine, which I've already stated before, but not like you read anything.
    Wine is so much more than just a loader. If you're exclusively using Wine, you're really trying not to use Linux, not least because it just gets in the way of most of Linux' native features and capabilities, not to mention the userland ecosystem for which you have such seething contempt.

    Originally posted by Weasel View Post
    Also this is NOT a Linux forum, it's an open source forum (about open source I mean). Wine is open source project that can load DLLs. Got a problem with that? Sounds perfectly valid to me.
    It's like 98% Linux and Linux-centric opensource. Reasonable people will agree that coming on here and shitposting about Linux is trolling behavior.

    Leave a comment:


  • F.Ultra
    replied
    Originally posted by moonshadow565 View Post

    I'm aware of that it can load multiple architectures which is sadly only extension on elf (which afaik isn't accept into mainline linux kernel).
    I am more interested in multiple libraries per process problem that has beeb discused on this thread...
    Acording to wikipedia Macho-o has something called 2 level namespace, is this related to this probelm?
    The darling project implements Macho-o loader for linux so i would be more interested to see that as alternative to elf than dll.
    Hope some experts can shed some light on this
    The two-level namespace in Mach-o (the name is Mach-o and not Macho-o) means that each imported symbol have their corresponding library defined.

    Lets say that we have one process A and three shared libraries B, C and D.

    Process A links with B to use function1() and with C to use function2().
    Library C links with D to use function1() in it's function2().

    We now have two different functions named function1() (one from B and one from D).

    In a non-versioned ELF situation we end up with function1() from B being used both when it's called from A and when it's called from function2() in C.

    On Mach-o however since each exported symbol have their respective library name attached function1() from B will be used when called from A and function1() from D will be used when called from function2() in C.

    Leave a comment:

Working...
X