1

gcc 4.8.4 が示す次の動作を説明できません。次のコード スニペットの名前をpow_main.c.

#include <stdio.h>
#include <math.h>

int main()
{
    printf("%lf\n", pow(2, 10));
    return 0;
}

次のコマンドラインを使用してプログラムをコンパイルしています。

gcc -c -O0 -Wall pow_main.c -o pow_main.o 

-cプログラムをコンパイル ( ) しているだけで、リンクしていないことに注意してください。また、コンパイラの最適化はすべて無効になっています ( -O0)。オブジェクト ファイルに含まれるシンボルを調べると、次のことがわかります。

$ nm pow_main.o
0000000000000000 T main
                 U printf

私には、コンパイラがメソッドへの参照をライブラリpowから静的に解決したか、インラインコードで呼び出しを最適化したようです。mathpow

  1. powオブジェクトファイルにシンボルが存在しないのはなぜですか?
  2. 外部参照を解決する責任があるのはリンカではなく、静的か動的か?
  3. オブジェクト ファイルに未定義の ( U) シンボルがpow存在するべきではありませんか?pow_main.o

プラットフォームの詳細は次のとおりです。

gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) 

編集: 私の 2 つの疑いの 1 つが正しいようです。gcc は式を事前に計算し、定数に置き換えました。

00000000004006dd <main>:
  4006dd:   55                      push   %rbp
  4006de:   48 89 e5                mov    %rsp,%rbp
  4006e1:   48 83 ec 10             sub    $0x10,%rsp
  4006e5:   48 b8 00 00 00 00 00    movabs $0x4090000000000000,%rax
  4006ec:   00 90 40 
  4006ef:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  4006f3:   f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
  4006f8:   bf e4 07 40 00          mov    $0x4007e4,%edi
  4006fd:   b8 01 00 00 00          mov    $0x1,%eax
  400702:   e8 b9 fe ff ff          callq  4005c0 <printf@plt>
  400707:   48 ba 00 00 00 00 00    movabs $0x4024000000000000,%rdx
  40070e:   00 24 40 
  400711:   48 b8 00 00 00 00 00    movabs $0x4000000000000000,%rax
  400718:   00 00 40 
  40071b:   48 89 55 f8             mov    %rdx,-0x8(%rbp)
  40071f:   f2 0f 10 4d f8          movsd  -0x8(%rbp),%xmm1
  400724:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  400728:   f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
  40072d:   e8 7e fe ff ff          callq  4005b0 <power@plt>
  400732:   f2 0f 11 45 f8          movsd  %xmm0,-0x8(%rbp)
  400737:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  40073b:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  40073f:   f2 0f 10 45 f8          movsd  -0x8(%rbp),%xmm0
  400744:   bf e4 07 40 00          mov    $0x4007e4,%edi
  400749:   b8 01 00 00 00          mov    $0x1,%eax
  40074e:   e8 6d fe ff ff          callq  4005c0 <printf@plt>
  400753:   b8 00 00 00 00          mov    $0x0,%eax
  400758:   c9                      leaveq 
  400759:   c3                      retq   
  40075a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

ここでの問題は、そのような最適化をオフにする方法O0です。

4

2 に答える 2

1

pow(2, 10)コンパイラは、コンパイル時にの結果が 1024 になると計算できるので、そのようにします。また、最適化レベル 0 の場合でも、コンパイル時に一部の計算が行われるようです。したがって、数学ライブラリをプログラムにリンクする必要はありません。

もちろん、Mac OS X などの一部のシステムでは、数学ライブラリを指定する必要はありません-lm。数学関数はメインの C ライブラリにあります。

于 2015-08-28T06:03:29.580 に答える
0
  1. 専用の CPU 命令で実装するか、完全に最適化して定数 1024 に置き換えることができます。
  2. はい、シンボルがあれば。
  3. 必ずしもそうではありません。

ライブラリを静的にリンクすると、通常T、 の出力に でマークされた解決されたシンボルが表示されますnm

于 2015-08-28T06:07:49.593 に答える