GCC differently treats an object and a static library regarding undefined symbols












1















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?










share|improve this question



























    1















    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?










    share|improve this question

























      1












      1








      1


      0






      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?










      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 21 '18 at 14:29









      Alexander SamoylovAlexander Samoylov

      106110




      106110
























          2 Answers
          2






          active

          oldest

          votes


















          3














          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.






          share|improve this answer


























          • 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



















          2














          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.






          share|improve this answer


























          • 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











          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          3














          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.






          share|improve this answer


























          • 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
















          3














          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.






          share|improve this answer


























          • 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














          3












          3








          3







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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



















          • 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













          2














          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.






          share|improve this answer


























          • 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
















          2














          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.






          share|improve this answer


























          • 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














          2












          2








          2







          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.






          share|improve this answer















          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.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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



















          • 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


















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

          Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

          A Topological Invariant for $pi_3(U(n))$