C言語ソースコードをGCCを利用せずに手動でコンパイルする
C言語の知識、経験が全く無く、C言語のソースを手動でコンパイル、リンクしたら、実行時にセグフォが発生。
動かない原因の調査と動くところまでを確認したログ。
環境情報
Linux カーネル
Linux version 4.19.121-linuxkit (root@buildkitsandbox) (gcc version 9.2.0 (Alpine 9.2.0)) #1 SMP Tue Dec 1 17:50:32 UTC 2020
GCC
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
NASM
NASM version 2.10.07 compiled on Jun 9 2014
GCCを利用したコンパイル
ソースコード
a.c
#include<stdio.h>
void main(void) {
printf("hello, world\n");
}
コンパイル
実行ファイル作成
# gcc a.c
実行
# ./a.out
hello, world
GCCを利用すると当たり前に動く
GCC(コンパイラドライバ)を利用しないコンパイル
まずはGCCの実行内容を確認
# gcc -v a.c
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v a.c -quiet -dumpbase a.c -mtune=generic -march=x86-64 -auxbase a -version -o /tmp/cclk9k31.s
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-39) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-39), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
End of search list.
GNU C (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-39) (x86_64-redhat-linux)
compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-39), GMP version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: edd9a53947039836c859e437e8c9af72
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccDvQV5t.o /tmp/cclk9k31.s
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version 2.27-43.base.el7_8.1
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccDvQV5t.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
抜粋
C言語ソースコード => アセンブリ言語
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v a.c -quiet -dumpbase a.c -mtune=generic -march=x86-64 -auxbase a -version -o /tmp/cclk9k31.s
アセンブリ言語 => オブジェクトファイル
as -v --64 -o /tmp/ccDvQV5t.o /tmp/cclk9k31.s
オブジェクトファイル => 実行ファイル(ELF)
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccDvQV5t.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
ざっくりやっていることは C言語 => アセンブリ => オブジェクトファイル => 実行ファイル
各ステップで利用しているコマンドを確認したので手で実行する
コンパイル
C言語ソースコード => アセンブリ言語
# /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 a.c
アセンブリ言語 => オブジェクトファイル
# as a.s
オブジェクトファイル => 実行ファイル(ELF)
# ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a a.out \
/usr/lib64/crt1.o \
/usr/lib64/crti.o \
/usr/lib64/crtn.o \
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o \
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o \
-lc
実行
# ./a
hello, world
これはcrt
と-lc(libc)
をリンクしているので、動く
躓いた点として、リンク対象にcrt
や-lc
を含めずに実行ファイルを作成、実行、_start
やputs
がないと言われた
# ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a a.out
ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0
a.out: In function `main':
a.c:(.text+0xa): undefined reference to `puts'
crt はスタートアップルーチンが含まれるオブジェクト
-lc はlibc(基本的な機能のライブラリ、putsやexit)
なので一緒にリンクしてあげる
スタートアップルーチン、libcをリンクしない実行ファイルの作成
ソースコード
a.c
void print(char *str, int length);
void main(void) {
char *str = "Hello, World!\n";
print(str, 14);
}
b.asm
global _start, print
extern main
exit:
mov eax, 60
syscall
print:
mov rdx, rsi
mov esi, edi
mov eax, 1
mov edi, 1
syscall
ret
_start:
call main
call exit
ソースコードの説明
ldはデフォルトで_startがプログラムの開始位置となり、スタートアップルーチンをリンクしないため自前でアセンブリに関数を用意
libcをリンクしないため、直接アセンブリから文字出力を実行
コンパイル
C言語ソースコード => アセンブリ言語
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 a.c
アセンブリ言語 => オブジェクトファイル
as a.s
アセンブリ言語 => オブジェクトファイル※nasmの書き方しか分からないので
nasm -f elf64 b.asm
オブジェクトファイル => 実行ファイル(ELF)
ld -o a a.out b.o
実行
# ./a
hello, world
できた
Author And Source
この問題について(C言語ソースコードをGCCを利用せずに手動でコンパイルする), 我々は、より多くの情報をここで見つけました https://qiita.com/qon/items/337adcbf49b577265cd9著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .