Discussion:
ld order of .o and .a
(too old to reply)
Siri Cruise
2021-02-11 21:39:42 UTC
Permalink
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.

I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Rainer Weikusat
2021-02-11 23:42:45 UTC
Permalink
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
It is.
Siri Cruise
2021-02-12 00:05:39 UTC
Permalink
In article
Post by Rainer Weikusat
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
It is.
I had two cc in the makefile. To test I changed the one not
called and missed the other. So changing the order didn't appear
to work. It wasn't until I changed the order in both places that
I realised linux is still using an ancient and archaic ld.

Now I get to fix new and exciting crap.
#define _GNU_SOURCE
#define __USE_GNU
Oh, that's neat. Linux decided when I include a file, I didn't
really want to include the file unless I say the magick
incantation first.

https://getyarn.io/yarn-clip/a8285b76-3c16-4ff4-b3e6-91463bb46bd1
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Rainer Weikusat
2021-02-12 00:21:30 UTC
Permalink
Post by Siri Cruise
Post by Rainer Weikusat
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
It is.
I had two cc in the makefile. To test I changed the one not
called and missed the other. So changing the order didn't appear
to work. It wasn't until I changed the order in both places that
I realised linux is still using an ancient and archaic ld.
That's the GNU binutils linker and changing the default behaviour would
probably break backwards-compatibility.
Post by Siri Cruise
Now I get to fix new and exciting crap.
#define _GNU_SOURCE
#define __USE_GNU
Oh, that's neat. Linux decided when I include a file, I didn't
really want to include the file unless I say the magick
incantation first.
"Linux" didn't decide anything (that's a program, BTW), the GNU C
library offers a superset of UNIX features and various traditional
interfaces provided by BSD and other UNIX. Also, it supports GNU
specific and Linux specific features. This means one will sometimes have
to use feature selection macros as the default (set of stuff defined by
headers) is meant to be "UNIX compatible".

IMHO, that's (at best) a minor nuisance and usually documented.

Both this and the linker behaviour are ultimatively policy decisions and
people are bound to disagre re: What exactly constitutes a sensible
policy.

NB: I don't claim that the default policy used on Linux would be
sensible: Sometimes, it's going to make sense, and some other times, it
won't and that's just one of the annoyances one has to deal with when
writing code.
Siri Cruise
2021-02-12 03:26:33 UTC
Permalink
In article
Post by Rainer Weikusat
That's the GNU binutils linker and changing the default behaviour would
probably break backwards-compatibility.
I don't see how. Modern machines have enough memory to put
definitions in a hash table by name and object file. If the
library name is repeated, a double indexing allows the previous
definitions to be deleted as the new object definitions are
loaded. I have no pity anyone using load order for such esoteric
reasons that that would still break.

I started unices in 1980. I appreciated at the time why ld had to
be stupid. I didn't expect people demand ld remain stupid when vm
broke the 65KB and then 4MB boundaries.

Why are all manhole covers round? Because manholes are round. Why
are all manholes round? Because manhole covers are round.
Post by Rainer Weikusat
IMHO, that's (at best) a minor nuisance and usually documented.
I got all this running on a mac, now I want to get it compiled on
linux. I've already #ifdeffed what I know to be system dependent;
I expected things like asprintf or dlfcn.h to be system
dependent; I didn't expect to study man pages again or read
include files. One of _GNU_SOURCE or __USE_GNU is in the manpage;
the other has to be discoverred from include files.

I've already done 95% of the port before even getting on linux. I
don't appreciate doing another 37% of the port because someone
decided to warn me that I'm doing a port so I better be careful.

(language warning)
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Philip Guenther
2021-02-12 05:20:41 UTC
Permalink
Post by Siri Cruise
In article
Post by Rainer Weikusat
That's the GNU binutils linker and changing the default behaviour would
probably break backwards-compatibility.
I don't see how. Modern machines have enough memory to put
definitions in a hash table by name and object file. If the
library name is repeated, a double indexing allows the previous
definitions to be deleted as the new object definitions are
loaded. I have no pity anyone using load order for such esoteric
reasons that that would still break.
I started unices in 1980. I appreciated at the time why ld had to
be stupid. I didn't expect people demand ld remain stupid when vm
broke the 65KB and then 4MB boundaries.
"History and economics matter"

I assume I'm mistaken in part of this, but I believe that binutils ld exists because Cygnus needed a linker and had (created) the paying market of developers for embedded CPUs to support the core development; porting to the commercial unices was a stream of contributions on top of that, but the base exists because there were enough companies who could spend less by paying Cygnus to provide the common work.

The second linker, gold, exists because a single company (Google) had resources to spare and saw a benefit worth the cost, to the point that I have heard that for some period of time (and still?) Chrome on { Android, Linux } could only be linked with gold and not with binutils ld because it's Just Too Big.

However, gold is *not* a 100% replacement for binutils ld. both because of what might be called "differences in implementation defined behavior" (for the targets it supports) and because the latter supports _many_ more targets. The former means that making it the default would cause stuff to break which worked before and thus cost OS integrator effort, while the latter meant that no matter how much effort was spent on that you could never drop binutils ld. As an OS integrator, if you'll always have to deal with binutils ld then why waste time on gold? Let that cost be carried by the software projects which required it.

The third linker, lld in the llvm project, again seems to exist because a company had needs not met by binutils ld (license, performance, support for execute-only-memory, whatever) and funded it and then the developers found an umbrella (llvm project) under which that could be shared and become a more inclusive community. Unlike gold, the differences from binutils ld (licence, performance, etc) where substantial enough for at least some OS integrators to get behind it and help build its community. But still, it hasn't killed binutils ld because it is not a complete replacement.


Meanwhile, for the majority of developers NONE OF THIS MATTERS. Most developers never do anything big enough or complex enough for the linker to matter enough for them to spend any time arguing for a faster linker, particularly if there are others arguing against that for reasons of license ("politics"), compatibility, or disenfranchisement (platform support). When concentrated costs are weighed against diverse benefits (or concentrated benefits vs diverse costs), the concentrated forces tend to win because it _matters_ to them.

So, we all have to deal with a sucky default linker on Linux because the groups that benefit from binutils being the default are concentrated while very few of the rest of us suffer enough to spend effort fighting about it.


Philip Guenther
Rainer Weikusat
2021-02-12 15:28:30 UTC
Permalink
Post by Siri Cruise
Post by Rainer Weikusat
That's the GNU binutils linker and changing the default behaviour would
probably break backwards-compatibility.
I don't see how. Modern machines have enough memory to put
definitions in a hash table by name and object file. If the
library name is repeated, a double indexing allows the previous
definitions to be deleted as the new object definitions are
loaded. I have no pity anyone using load order for such esoteric
reasons that that would still break.
If the behaviour is order dependent (and has been for decades) all kinds
of build system code everybody of which prefers to pretend that doesn't
really exist (and nobody or almost nobody really understands) will have
acquired implicit order dependencies and consequently, break in
seriously strange ways once the behaviour changes.

This was presumably already true by the time the bintutils linker was
written.

[...]
Post by Siri Cruise
Post by Rainer Weikusat
IMHO, that's (at best) a minor nuisance and usually documented.
I got all this running on a mac, now I want to get it compiled on
linux. I've already #ifdeffed what I know to be system dependent;
I expected things like asprintf or dlfcn.h to be system
dependent; I didn't expect to study man pages again or read
include files.
That's a wrong expectation, then. Mac basically means FreeBSD and by
default, BSD-features available in glibc won't be exposed to application
code. That's just how it is. And there's little point to "wail and gnash
one's teeth" about it, as that doesn't solve any problem.

Different systems are actually different, still today, despite there's
much less variety in the space of "what matters in practice".
Siri Cruise
2021-02-12 15:49:07 UTC
Permalink
In article
Post by Rainer Weikusat
That's a wrong expectation, then. Mac basically means FreeBSD and by
default, BSD-features available in glibc won't be exposed to application
I used SVID unices before macosx. It's not going back SVIDish
that bothers me.

I have already looked up things like dlfcn.h and readelf for
linux and #ifdef for mac and linux. However dlfcn.h didn't work.
I looked at more recent manpage. It didn't give the incantation.
It wasn't until I read the file itself that I saw the crap.

So you're saying the right expectation is not write what should
be portable code, but to expect to read any and all include files
and bash through by trial and error?
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Rainer Weikusat
2021-02-12 18:04:56 UTC
Permalink
Post by Siri Cruise
Post by Rainer Weikusat
That's a wrong expectation, then. Mac basically means FreeBSD and by
default, BSD-features available in glibc won't be exposed to application
I used SVID unices before macosx. It's not going back SVIDish
that bothers me.
I have already looked up things like dlfcn.h and readelf for
linux and #ifdef for mac and linux. However dlfcn.h didn't work.
I looked at more recent manpage. It didn't give the incantation.
It wasn't until I read the file itself that I saw the crap.
Presumably, the refers to using RTLD_DEFAUL and/ or RTLD_NEXT as first
argument to dlsym. There's a bit of a documentation mess here: There's a
manpage for all of libdl dated 2008-12-06 which states

The symbols RTLD_DEFAULT and RTLD_NEXT are defined by <dlfcn.h> only
when _GNU_SOURCE was defined before including it.

in the notes section. A 2015-08-08 manpage for dlsym only omits
this. Finally, there's a 2017-09-15 version which documents this in the
description section.

There's a real bit of "Welcome to the Linuxverse!" here: A set of
independently moving parts orbiting around each other at different
speeds who get constantly broken and unbroken by different people and
nobody in charge of destilling something coherent from that.

Nevertheless. _GNU_SOURCE is sufficient. _USE_GNU is an internal macro
automatically defined by features.h if needed.

Eg, this program compiles

-----
#define _GNU_SOURCE 1
#include <dlfcn.h>

int main(void)
{
dlsym(RTLD_NEXT, "rtld_prev");
return 0;
}
Siri Cruise
2021-02-13 09:16:53 UTC
Permalink
In article
Post by Rainer Weikusat
Post by Siri Cruise
Post by Rainer Weikusat
That's a wrong expectation, then. Mac basically means FreeBSD and by
default, BSD-features available in glibc won't be exposed to application
I used SVID unices before macosx. It's not going back SVIDish
that bothers me.
I have already looked up things like dlfcn.h and readelf for
linux and #ifdef for mac and linux. However dlfcn.h didn't work.
I looked at more recent manpage. It didn't give the incantation.
It wasn't until I read the file itself that I saw the crap.
Presumably, the refers to using RTLD_DEFAUL and/ or RTLD_NEXT as first
argument to dlsym. There's a bit of a documentation mess here: There's a
manpage for all of libdl dated 2008-12-06 which states
Anyway little linux victory. I wrote some code for macosx that
consulting a line number file a signal handler can print a
traceback from the failing stack frame giving function name and
line number. I've been using it for a while on macosx, and
according to the documentation it should work on linux. Hoorah!
It finally does. So now on any kind of abort my signal handlers
can give me

0x0000000000401754 debugtraceback [debugsymbol.c:96] (a)
0x0000000000400f57 catchsignal [a.c:118] (a)
0x0000000000000012
0x00007f2bb76533d7 gsignal + 55 (libc.so.6)
0x00007f2bb7654ac8 abort + 328 (libc.so.6)
0x00007f2bb7bef75b d [aux.c:5] (aux.so)
0x00007f2bb7bef781 c [aux.c:10] (aux.so)
0x0000000000400f9d b [a.c:141] (a)
0x0000000000400fe2 a [a.c:146] (a)
0x000000000040107e main [a.c:153] (a)
0x00007f2bb763f555 __libc_start_main + 245 (libc.so.6)
0x0000000000000012

I want to eventually embed the line number data into the
binaries, but for now a separate file works.
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Philip Guenther
2021-02-12 05:31:00 UTC
Permalink
Post by Siri Cruise
In article
Post by Rainer Weikusat
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
It is.
I had two cc in the makefile. To test I changed the one not
called and missed the other. So changing the order didn't appear
to work. It wasn't until I changed the order in both places that
I realised linux is still using an ancient and archaic ld.
Now I get to fix new and exciting crap.
#define _GNU_SOURCE
#define __USE_GNU
Hmm, in all the glibc versions I have on hand, only _GNU_SOURCE is necessary; if that's defined then the internal <features.h> header will then define __USE_GNU, such that having defined the former (which has other effects too) the latter will always be defined. That matches the glibc info <spit> documentation only covering the former.

If you've found a case where both of those are required, the glibc people will presumably take it as bug and request an example so they can fix it (...or explain how what you're doing is wrong...)


Philip Guenther
Siri Cruise
2021-02-12 06:31:59 UTC
Permalink
In article
Post by Philip Guenther
If you've found a case where both of those are required, the glibc people
will presumably take it as bug and request an example so they can fix it
(...or explain how what you're doing is wrong...)
My experience is bug reporting is designed to discourage bug
reporting. And I had never got a response. So I don't do it any
longer. I patch with a few choice expletives and continue. I got
my ed scripts to force configure and makefiles actually work.

The only response I got was with exiv2. If I find any new
problems there, I will give them the fix.

If people really want feedback, they have acknowledge feedback
and also realise sometimes the people reporting know more than
they do.
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Nicolas George
2021-02-12 10:00:18 UTC
Permalink
Siri Cruise , dans le message
Post by Siri Cruise
I realised linux is still using an ancient and archaic ld.
In your desire to badmouth Linux, you are being wrong and inaccurate.

Linux's linker, i.e. GNU ld, used to accept libraries in any order. I have
makefiles from less than six years ago that used it (through pkg-config,
it's more expensive to control the order).

It was deliberately changed to adhere to the standards more closely, and
avoid letting developers write non-portable build rules.
Siri Cruise
2021-02-11 23:50:14 UTC
Permalink
In article
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
Crap. It is order sensitive. That is so 1970s. Yeah, back in the
good old days when one megabyte was a huge disk drive and real
memory was mere kilobytes, it was an acceptable limitation not to
keep library contents during ld.

This reinforces my belief linux is for children not actual
software.
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
James K. Lowden
2021-02-14 20:09:26 UTC
Permalink
On Thu, 11 Feb 2021 15:50:14 -0800
Post by Siri Cruise
Crap. It is order sensitive. That is so 1970s.
You say that likes it's a bad thing. It's well known that the 1970s
were a Golden Age. Among other things, they gave us troff and unleaded
gasoline.

I don't understand your objection, on practical grounds. Unless you
have clrcular library dependencies -- and why would you? -- then surely
you *want* the linker to be order-dependent, so that functions defined
by earlier libraries override later definitions deterministically.

If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two libraries?

--jkl
Kaz Kylheku
2021-02-14 20:35:06 UTC
Permalink
["Followup-To:" header set to comp.unix.programmer.]
Post by James K. Lowden
On Thu, 11 Feb 2021 15:50:14 -0800
Post by Siri Cruise
Crap. It is order sensitive. That is so 1970s.
You say that likes it's a bad thing. It's well known that the 1970s
were a Golden Age. Among other things, they gave us troff and unleaded
gasoline.
I don't understand your objection, on practical grounds. Unless you
have clrcular library dependencies -- and why would you? -- then surely
you *want* the linker to be order-dependent, so that functions defined
by earlier libraries override later definitions deterministically.
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two libraries?
"error: multiply defined symbol foo", I would hope.
--
TXR Programming Language: http://nongnu.org/txr
Cygna: Cygwin Native Application Library: http://kylheku.com/cygnal
James K. Lowden
2021-02-14 22:19:05 UTC
Permalink
On Sun, 14 Feb 2021 20:35:06 -0000 (UTC)
Post by Kaz Kylheku
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two
libraries?
"error: multiply defined symbol foo", I would hope.
No, of course not. The One Definition Rule applies to data, not
functions.

You're not suggesting, are you, that I can't write my own memcpy, put
it in memcpy.a, and link it into my C program, overriding the function
defined in libc?

One of us doesn't understand the other. I prepared for that person to
be me, but right now I'm baffled at the discussion.

--jkl
Nicolas George
2021-02-14 22:39:03 UTC
Permalink
"James K. Lowden" , dans le message
Post by James K. Lowden
You're not suggesting, are you, that I can't write my own memcpy, put
it in memcpy.a, and link it into my C program, overriding the function
defined in libc?
Actually, no, you cannot do that: if you properly included <string.h>, the
compiler is allowed to replace a call to memcpy by any code that has the
same semantic, including inline code without any function call, or calls to
function named differently. And in practice, they do.
Kaz Kylheku
2021-02-15 00:08:36 UTC
Permalink
Post by James K. Lowden
On Sun, 14 Feb 2021 20:35:06 -0000 (UTC)
Post by Kaz Kylheku
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two
libraries?
"error: multiply defined symbol foo", I would hope.
No, of course not. The One Definition Rule applies to data, not
functions.
A rule by that name is found in C++. C++ does not allow multiply
defined functions, other than inline functions.

$ g++ multiple.cc
multiple.cc: In function ‘void foo()’:
multiple.cc:5:6: error: redefinition of ‘void foo()’
void foo()
^~~
multiple.cc:1:6: note: ‘void foo()’ previously defined here
void foo()
^~~

C++ has overloading; a function is multiply defined if the same overload
of it is multiply defined.
Post by James K. Lowden
You're not suggesting, are you, that I can't write my own memcpy, put
it in memcpy.a, and link it into my C program, overriding the function
defined in libc?
Since something like that could happen by accident, there is something
to be said for having it diagnosed if it literally occurs as above.

Yet, some sort of documented extension can exist for doing the override.

It could just be the above, with the presence of the diagnostic.

In the GNU/Linux environment, if you write your own functions that clash
with glibc functions, you're not "overriding" anything. Libc calls the
original functions using their their internal names.

This is necessary for basic ISO C conformance. A strictly conforming ISO
C program can define a function called isatty() or read(). These
definitions must not be mistakenly called by, say, stdio routines.

The mechanism is supported by "weak symbols". When you write a read()
function that's an ordinary symbol which "wins" over the weak symbol.
That's a dynamic linking concept which has nothing to do with static
"ld" or is library order.
--
TXR Programming Language: http://nongnu.org/txr
Cygna: Cygwin Native Application Library: http://kylheku.com/cygnal
James K. Lowden
2021-02-15 20:44:27 UTC
Permalink
On Mon, 15 Feb 2021 00:08:36 -0000 (UTC)
Post by Kaz Kylheku
Post by James K. Lowden
You're not suggesting, are you, that I can't write my own memcpy,
put it in memcpy.a, and link it into my C program, overriding the
function defined in libc?
Since something like that could happen by accident, there is something
to be said for having it diagnosed if it literally occurs as above.
Yet, some sort of documented extension can exist for doing the
override.
It could just be the above, with the presence of the diagnostic.
I should have known better than to pick a C standard library function.
OTOH, I learned something. After 4 decades, the only reasonable
conclusion I can draw is that C programming is unlearnable.

On the 3rd hand, I've been overriding functions since ever, and don't
ever remember seeing a linker error if the same function appeared in
multiple libraries. Here is a quick example:

$ for F in nsymbol.c [ab].c
Post by Kaz Kylheku
do nl $F; done
1 extern void foo(void);

2 int main(int argc, char *argv[])
3 {
4 foo();
5 return 0;
6 }
1 #include <stdio.h>

2 void foo(void) {
3 printf( "using %s:%s\n", __FILE__, __func__ );
4 }
1 #include <stdio.h>

2 void foo(void) {
3 printf( "using %s:%s\n", __FILE__, __func__ );
4 }

$ make -B nsymbol
cc -c -o a.o a.c
ar -r liba.a a.o
cc -c -o b.o b.c
ar -r libb.a b.o
cc -std=c11 -onsymbol nsymbol.c -L. -la -lb

$ ./nsymbol
using a.c:foo

That is the only behavior I ever remember seeing, and the only behavior
I'd ever expect.

We're outside the rules of the C standard here, afaik, and into the
wolly world of whatever it is linkers do. I contend it's normal, and
useful, and traditional for the linker to resolve symbols from
libraries in the order in which the libraries are presented, full
stop. Perhaps that behavior was the product of limited resources in
the PDP/11 era, but it is also convenient, flexible, and
deterministic.

--jkl
Rainer Weikusat
2021-02-15 22:40:41 UTC
Permalink
"James K. Lowden" <***@speakeasy.net> writes:

[...]
Post by James K. Lowden
I contend it's normal, and
useful, and traditional for the linker to resolve symbols from
libraries in the order in which the libraries are presented, full
stop. Perhaps that behavior was the product of limited resources in
the PDP/11 era, but it is also convenient, flexible, and
deterministic.
,----
| The argument routines are concatenated in the orderspecified. The entry
| point of the output is the beginning of the first routine. If any
| argument is a library, it is searched, and onlythose routines defining
| an unresolved external reference are loaded. If any routine loaded from
| a library refers toan undefined symbol which does not become defined by
| the end of the library, the library is searched again.
`----

ld(1) manpage, Unix 1st ed, as available here: http://man.cat-v.org/unix-1st/1/ld

This behaviour predates C by some time.

Ben Bacarisse
2021-02-15 02:01:18 UTC
Permalink
Post by James K. Lowden
On Sun, 14 Feb 2021 20:35:06 -0000 (UTC)
Post by Kaz Kylheku
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two
libraries?
"error: multiply defined symbol foo", I would hope.
No, of course not. The One Definition Rule applies to data, not
functions.
Maybe I've lost the context, but in C it applies to both. The trouble
is that the rule is expressed in terms of "external definitions" and
that is a concept that apples to the program text. The rule is probably
supposed include definitions in libraries (where these is no program
text) but a lawyer could probably argue it either way.

Anyway, the rule (however one interprets the case of libraries) applies
to any identifier with external linkage -- both objects and functions.
--
Ben.
James Kuyper
2021-02-15 03:58:56 UTC
Permalink
Post by James K. Lowden
On Sun, 14 Feb 2021 20:35:06 -0000 (UTC)
Post by Kaz Kylheku
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two
libraries?
"error: multiply defined symbol foo", I would hope.
No, of course not. The One Definition Rule applies to data, not
functions.
You're not suggesting, are you, that I can't write my own memcpy, put
it in memcpy.a, and link it into my C program, overriding the function
defined in libc?
One of us doesn't understand the other. I prepared for that person to
be me, but right now I'm baffled at the discussion.
The following citations are from the C2011 standard:

"An external definition is an external declaration that is also a
definition of a function (other than an inline definition) or an object.
If an identifier declared with external linkage is used in an expression
(other than as part of the operand of a sizeof or _Alignof operator
whose result is an integer constant), somewhere in the entire
program there shall be exactly one external definition for the
identifier; otherwise, there shall be no more than one." (6.9p5).

Notice that the rules are the same whether the identifier identifies a
function or an object.

"If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a
constraint or runtime-constraint is violated, the behavior is
undefined." (4p2).

"All identifiers with external linkage in any of the following
subclauses (including the future library directions) and errno are
always reserved for use as identifiers with external linkage." (7.1.3p1)

Note that memcpy one of the identifiers with external linkage in the
following subclauses.

"If the program declares or defines an identifier in a context in which
it is reserved (other than as allowed by 7.1.4) ... the behavior is
undefined." (7.1.3p2).

Providing a definition for memcpy with external linkage is not one of
the cases allowed by 7.1.4.

It's quite common for implementations to define the behavior when
multiple definitions are available, in a way that's convenient. The
behavior you describe is one example of that. However, they are not
required to do so.
Kaz Kylheku
2021-02-15 15:27:09 UTC
Permalink
Post by James Kuyper
It's quite common for implementations to define the behavior when
multiple definitions are available, in a way that's convenient.
That way remains convenient only when:

1. the definitions are all controlled by your program, and do not
clash with anything in the system.

2. the definitions are identical (or "similar" according to some rules).
--
TXR Programming Language: http://nongnu.org/txr
Cygna: Cygwin Native Application Library: http://kylheku.com/cygnal
Siri Cruise
2021-02-15 02:19:11 UTC
Permalink
In article
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two libraries?
Put the symbol definitions in a hash table. The table is updated
to contain the last definition so far seen.
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Rainer Weikusat
2021-02-15 14:53:14 UTC
Permalink
Post by Siri Cruise
Post by James K. Lowden
If it doesn't work that way, how is the linker supposed to choose
between two implementations of a function defined in two libraries?
Put the symbol definitions in a hash table. The table is updated
to contain the last definition so far seen.
That's still order-dependent, then, just in the opposite order.
Kaz Kylheku
2021-02-12 00:24:42 UTC
Permalink
Post by Siri Cruise
Is linux ld sensitive to the file order the way macosx ld isn't?
That would be so 1970s.
It's sensitive to .a order, not to .o order.
Post by Siri Cruise
I get a file list like -Llib -lgc -lcord ... -lm -liconv ... x.o
y.o z.o . Loads fine on macosx. On linux it whines about missing
symbols that I verify with nm are in libgc.a .
You can use the -( and -) arguments to parenthesize groups of .a
files which are then mutually resolved.

-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either
explicit file names, or -l options.

The specified archives are searched repeatedly until no new
undefined references are created. Normally, an archive is searched
only once in the order that it is specified on the command line.
If a symbol in that archive is needed to resolve an undefined
symbol referred to by an object in an archive that appears later on
the command line, the linker would not be able to resolve that
reference. By grouping the archives, they all be searched
repeatedly until all possible references are resolved.

Using this option has a significant performance cost. It is best
to use it only when there are unavoidable circular references
between two or more archives.
--
TXR Programming Language: http://nongnu.org/txr
Cygna: Cygwin Native Application Library: http://kylheku.com/cygnal
Siri Cruise
2021-02-12 02:51:30 UTC
Permalink
Post by Kaz Kylheku
You can use the -( and -) arguments to parenthesize groups of .a
files which are then mutually resolved.
I'll have to remember that if it comes up again.
Post by Kaz Kylheku
Using this option has a significant performance cost. It is best
I'm more concerned about the cognitive costs than the performance
cost.
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
Discordia: not just a religion but also a parody. This post / \
I am an Andrea Doria sockpuppet. insults Islam. Mohammed
Loading...