GCC differently treats an object and a static library regarding undefined symbols
Recently I discoved that Linux linker does not fail due to undefined symbols from static libraries, however does fail due to the same undefined symbols if I link directly with te object files. Here is a simple example:
Source code:
$ cat main.c
int main() { return 0; }
$ cat src.c
int outerUnusedFunc() {
return innerUndefinedFunc();
}
int innerUndefinedFunc();
Creating *.o and *.a from it, comparing using "nm":
$ gcc -c -o main.o main.c
$ gcc -c -o src.o src.c
$ ar r src.a src.o
ar: creating src.a
$ nm src.o
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
$ nm src.a
src.o:
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
(Here we clearly see that both *.o and *.a contain the equal symbols list)
And now...
$ ld -o exe main.o src.o
src.o: In function `outerUnusedFunc':
src.c:(.text+0xa): undefined reference to `innerUndefinedFunc'
$ echo $?
1
$ ld -o exe main.o src.a
$ echo $?
0
What is the reason for GCC to treat it differenty?
gcc linker static-libraries undefined-symbol
add a comment |
Recently I discoved that Linux linker does not fail due to undefined symbols from static libraries, however does fail due to the same undefined symbols if I link directly with te object files. Here is a simple example:
Source code:
$ cat main.c
int main() { return 0; }
$ cat src.c
int outerUnusedFunc() {
return innerUndefinedFunc();
}
int innerUndefinedFunc();
Creating *.o and *.a from it, comparing using "nm":
$ gcc -c -o main.o main.c
$ gcc -c -o src.o src.c
$ ar r src.a src.o
ar: creating src.a
$ nm src.o
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
$ nm src.a
src.o:
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
(Here we clearly see that both *.o and *.a contain the equal symbols list)
And now...
$ ld -o exe main.o src.o
src.o: In function `outerUnusedFunc':
src.c:(.text+0xa): undefined reference to `innerUndefinedFunc'
$ echo $?
1
$ ld -o exe main.o src.a
$ echo $?
0
What is the reason for GCC to treat it differenty?
gcc linker static-libraries undefined-symbol
add a comment |
Recently I discoved that Linux linker does not fail due to undefined symbols from static libraries, however does fail due to the same undefined symbols if I link directly with te object files. Here is a simple example:
Source code:
$ cat main.c
int main() { return 0; }
$ cat src.c
int outerUnusedFunc() {
return innerUndefinedFunc();
}
int innerUndefinedFunc();
Creating *.o and *.a from it, comparing using "nm":
$ gcc -c -o main.o main.c
$ gcc -c -o src.o src.c
$ ar r src.a src.o
ar: creating src.a
$ nm src.o
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
$ nm src.a
src.o:
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
(Here we clearly see that both *.o and *.a contain the equal symbols list)
And now...
$ ld -o exe main.o src.o
src.o: In function `outerUnusedFunc':
src.c:(.text+0xa): undefined reference to `innerUndefinedFunc'
$ echo $?
1
$ ld -o exe main.o src.a
$ echo $?
0
What is the reason for GCC to treat it differenty?
gcc linker static-libraries undefined-symbol
Recently I discoved that Linux linker does not fail due to undefined symbols from static libraries, however does fail due to the same undefined symbols if I link directly with te object files. Here is a simple example:
Source code:
$ cat main.c
int main() { return 0; }
$ cat src.c
int outerUnusedFunc() {
return innerUndefinedFunc();
}
int innerUndefinedFunc();
Creating *.o and *.a from it, comparing using "nm":
$ gcc -c -o main.o main.c
$ gcc -c -o src.o src.c
$ ar r src.a src.o
ar: creating src.a
$ nm src.o
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
$ nm src.a
src.o:
U innerUndefinedFunc
0000000000000000 T outerUnusedFunc
(Here we clearly see that both *.o and *.a contain the equal symbols list)
And now...
$ ld -o exe main.o src.o
src.o: In function `outerUnusedFunc':
src.c:(.text+0xa): undefined reference to `innerUndefinedFunc'
$ echo $?
1
$ ld -o exe main.o src.a
$ echo $?
0
What is the reason for GCC to treat it differenty?
gcc linker static-libraries undefined-symbol
gcc linker static-libraries undefined-symbol
asked Nov 21 '18 at 14:29
Alexander SamoylovAlexander Samoylov
106110
106110
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
If you read the static-libraries
tag wiki
it will explain why no object files from src.a
are linked into your program, and therefore
why it doesn't matter what undefined symbols are referenced in them.
The difference between an object file foo.o
and a static library libfoo.a
, as linker inputs, is
that an object file is always linked into your program, unconditionally, whereas the same object file
in a static library library, libfoo.a(foo.o)
, is extracted from libfoo.a
and linked into
the program only if the linker needs it to carry on the linkage, as explained by the tag wiki.
Naturally, the linker will give errors only for undefined references in object files that are linked into the program.
The behaviour you are observing is behaviour of the linker, whether or not you invoke it via a GCC
front-end.
Giving the linker foo.o
tells it: I want this in the program. Giving the linker
libfoo.a
tells it: Here are some object files that you might or might not need.
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
add a comment |
In the second case — with static library — command line with says "build exe from main.o and add all required things from src.a".
ld
just ignores the library because no external symbols required for main.o
(outerUnusedFunc
is not referenced from main.o
).
But in the first case command line says "build exe from main.o and src.o".
ld
should place src.o
content into output file.
Hence, it obligate to analyze src.o
module, add outerUnusedFunc
into output file and resolve all symbols for outerUnusedFunc
despite it is unused.
You can enable garbage collection for code sections
gcc --function-sections -Wl,--gc-sections -o exe main.c src.c
In this case outerUnusedFunc
(as well as all other functions) will be placed
in separate section. ld
will see that this section unused (no symbols referenced). It will remove all the section from output file so that innerUndefinedFunc
would not be referenced and the symbol should not be resolved — the same result as for library case.
On the other hand, you can manually reference outerUnusedFunc
as "undefined" so that ld
should find it in library and add to output file.
ld -o exe main.o -u outerUnusedFunc src.a
in this case the same error (undefined reference to innerUndefinedFunc) will be produced.
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53414293%2fgcc-differently-treats-an-object-and-a-static-library-regarding-undefined-symbol%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
If you read the static-libraries
tag wiki
it will explain why no object files from src.a
are linked into your program, and therefore
why it doesn't matter what undefined symbols are referenced in them.
The difference between an object file foo.o
and a static library libfoo.a
, as linker inputs, is
that an object file is always linked into your program, unconditionally, whereas the same object file
in a static library library, libfoo.a(foo.o)
, is extracted from libfoo.a
and linked into
the program only if the linker needs it to carry on the linkage, as explained by the tag wiki.
Naturally, the linker will give errors only for undefined references in object files that are linked into the program.
The behaviour you are observing is behaviour of the linker, whether or not you invoke it via a GCC
front-end.
Giving the linker foo.o
tells it: I want this in the program. Giving the linker
libfoo.a
tells it: Here are some object files that you might or might not need.
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
add a comment |
If you read the static-libraries
tag wiki
it will explain why no object files from src.a
are linked into your program, and therefore
why it doesn't matter what undefined symbols are referenced in them.
The difference between an object file foo.o
and a static library libfoo.a
, as linker inputs, is
that an object file is always linked into your program, unconditionally, whereas the same object file
in a static library library, libfoo.a(foo.o)
, is extracted from libfoo.a
and linked into
the program only if the linker needs it to carry on the linkage, as explained by the tag wiki.
Naturally, the linker will give errors only for undefined references in object files that are linked into the program.
The behaviour you are observing is behaviour of the linker, whether or not you invoke it via a GCC
front-end.
Giving the linker foo.o
tells it: I want this in the program. Giving the linker
libfoo.a
tells it: Here are some object files that you might or might not need.
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
add a comment |
If you read the static-libraries
tag wiki
it will explain why no object files from src.a
are linked into your program, and therefore
why it doesn't matter what undefined symbols are referenced in them.
The difference between an object file foo.o
and a static library libfoo.a
, as linker inputs, is
that an object file is always linked into your program, unconditionally, whereas the same object file
in a static library library, libfoo.a(foo.o)
, is extracted from libfoo.a
and linked into
the program only if the linker needs it to carry on the linkage, as explained by the tag wiki.
Naturally, the linker will give errors only for undefined references in object files that are linked into the program.
The behaviour you are observing is behaviour of the linker, whether or not you invoke it via a GCC
front-end.
Giving the linker foo.o
tells it: I want this in the program. Giving the linker
libfoo.a
tells it: Here are some object files that you might or might not need.
If you read the static-libraries
tag wiki
it will explain why no object files from src.a
are linked into your program, and therefore
why it doesn't matter what undefined symbols are referenced in them.
The difference between an object file foo.o
and a static library libfoo.a
, as linker inputs, is
that an object file is always linked into your program, unconditionally, whereas the same object file
in a static library library, libfoo.a(foo.o)
, is extracted from libfoo.a
and linked into
the program only if the linker needs it to carry on the linkage, as explained by the tag wiki.
Naturally, the linker will give errors only for undefined references in object files that are linked into the program.
The behaviour you are observing is behaviour of the linker, whether or not you invoke it via a GCC
front-end.
Giving the linker foo.o
tells it: I want this in the program. Giving the linker
libfoo.a
tells it: Here are some object files that you might or might not need.
edited Nov 21 '18 at 22:28
answered Nov 21 '18 at 16:13
Mike KinghanMike Kinghan
31.1k766115
31.1k766115
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
add a comment |
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
Thanks for the link. It explained me what I didn't understand. I tried to create an atomic *.o from many *.o using "ld -r" and use this atomic *.o instead of the *.a. I couldn't understand why linking of an exe fails with the atomic *.o (due to unused symbols, but reported as "undefined") and passes with *.a. According to that article linker doesn't analyse *.o and takes all symbols from it, no matter if they called or not, while *.a it treats differently, that is extracts, checks each *.o inside *.a and includes all symbols from *.o to the exe if at least one symbol of that *.o is called.
– Alexander Samoylov
Dec 13 '18 at 16:46
add a comment |
In the second case — with static library — command line with says "build exe from main.o and add all required things from src.a".
ld
just ignores the library because no external symbols required for main.o
(outerUnusedFunc
is not referenced from main.o
).
But in the first case command line says "build exe from main.o and src.o".
ld
should place src.o
content into output file.
Hence, it obligate to analyze src.o
module, add outerUnusedFunc
into output file and resolve all symbols for outerUnusedFunc
despite it is unused.
You can enable garbage collection for code sections
gcc --function-sections -Wl,--gc-sections -o exe main.c src.c
In this case outerUnusedFunc
(as well as all other functions) will be placed
in separate section. ld
will see that this section unused (no symbols referenced). It will remove all the section from output file so that innerUndefinedFunc
would not be referenced and the symbol should not be resolved — the same result as for library case.
On the other hand, you can manually reference outerUnusedFunc
as "undefined" so that ld
should find it in library and add to output file.
ld -o exe main.o -u outerUnusedFunc src.a
in this case the same error (undefined reference to innerUndefinedFunc) will be produced.
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
add a comment |
In the second case — with static library — command line with says "build exe from main.o and add all required things from src.a".
ld
just ignores the library because no external symbols required for main.o
(outerUnusedFunc
is not referenced from main.o
).
But in the first case command line says "build exe from main.o and src.o".
ld
should place src.o
content into output file.
Hence, it obligate to analyze src.o
module, add outerUnusedFunc
into output file and resolve all symbols for outerUnusedFunc
despite it is unused.
You can enable garbage collection for code sections
gcc --function-sections -Wl,--gc-sections -o exe main.c src.c
In this case outerUnusedFunc
(as well as all other functions) will be placed
in separate section. ld
will see that this section unused (no symbols referenced). It will remove all the section from output file so that innerUndefinedFunc
would not be referenced and the symbol should not be resolved — the same result as for library case.
On the other hand, you can manually reference outerUnusedFunc
as "undefined" so that ld
should find it in library and add to output file.
ld -o exe main.o -u outerUnusedFunc src.a
in this case the same error (undefined reference to innerUndefinedFunc) will be produced.
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
add a comment |
In the second case — with static library — command line with says "build exe from main.o and add all required things from src.a".
ld
just ignores the library because no external symbols required for main.o
(outerUnusedFunc
is not referenced from main.o
).
But in the first case command line says "build exe from main.o and src.o".
ld
should place src.o
content into output file.
Hence, it obligate to analyze src.o
module, add outerUnusedFunc
into output file and resolve all symbols for outerUnusedFunc
despite it is unused.
You can enable garbage collection for code sections
gcc --function-sections -Wl,--gc-sections -o exe main.c src.c
In this case outerUnusedFunc
(as well as all other functions) will be placed
in separate section. ld
will see that this section unused (no symbols referenced). It will remove all the section from output file so that innerUndefinedFunc
would not be referenced and the symbol should not be resolved — the same result as for library case.
On the other hand, you can manually reference outerUnusedFunc
as "undefined" so that ld
should find it in library and add to output file.
ld -o exe main.o -u outerUnusedFunc src.a
in this case the same error (undefined reference to innerUndefinedFunc) will be produced.
In the second case — with static library — command line with says "build exe from main.o and add all required things from src.a".
ld
just ignores the library because no external symbols required for main.o
(outerUnusedFunc
is not referenced from main.o
).
But in the first case command line says "build exe from main.o and src.o".
ld
should place src.o
content into output file.
Hence, it obligate to analyze src.o
module, add outerUnusedFunc
into output file and resolve all symbols for outerUnusedFunc
despite it is unused.
You can enable garbage collection for code sections
gcc --function-sections -Wl,--gc-sections -o exe main.c src.c
In this case outerUnusedFunc
(as well as all other functions) will be placed
in separate section. ld
will see that this section unused (no symbols referenced). It will remove all the section from output file so that innerUndefinedFunc
would not be referenced and the symbol should not be resolved — the same result as for library case.
On the other hand, you can manually reference outerUnusedFunc
as "undefined" so that ld
should find it in library and add to output file.
ld -o exe main.o -u outerUnusedFunc src.a
in this case the same error (undefined reference to innerUndefinedFunc) will be produced.
edited Nov 21 '18 at 16:12
answered Nov 21 '18 at 14:40
ReAlReAl
7011216
7011216
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
add a comment |
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
That was exactly my question why GCC has more strict treatment about *.o. Do you know what is the logic behind such a behaviour?
– Alexander Samoylov
Nov 21 '18 at 15:28
1
1
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
@AlexanderSamoylov I updated the answer
– ReAl
Nov 21 '18 at 15:51
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53414293%2fgcc-differently-treats-an-object-and-a-static-library-regarding-undefined-symbol%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown