GCC编译器的常用命令及使用

一、用gcc生成静态库和动态库

在创建库函数之前,先来准备举例用的源程序,并将函数库的源程序编译成.o文件。

(1)编辑生成子程序hello.h、hello.c、main.c

先创建一个目录,用来保存用到的文件

xh@ubuntu:~$ mkdir test1
xh@ubuntu:~$ cd test1
xh@ubuntu:~/test1$ 

然后用vim、nano或gedit等文本编辑器生成所需要的3个文件。

xh@ubuntu:~/test1$ vim hello.c
#include<stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n",name);
}

利用vim编写完hello.c文件程序后,按esc键,输入:wq保存并退出;
在终端里输入nano hello.h编辑生成hello.h文件,写完之后按ctrl+X保存退出即可;

xh@ubuntu:~/test1$ nano hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif//HELLO_H

接着在终端里输入gedit main.c,创建编辑main.c文件;

xh@ubuntu:~/test1$ gedit main.c
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}

终端里面输入ls就可以看到我们刚刚建立的三个文件。

xh@ubuntu:~/test1$ ls
hello.c  hello.h  main.c

(2)将hello.c编译成.o文件

利用gcc命令编译hello.c

xh@ubuntu:~/test1$ gcc -c hello.c

在unbuntu终端运行ls命令看看是否生成了hello.o文件

xh@ubuntu:~/test1$ ls
hello.c  hello.h  hello.o  main.c

可以看到已经生成了hello.o文件

(3)由.o文件创建静态库

静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库名就是libmyhello.a。在创建静态库时,需要注意这点。创建静态库用ar命令。在终端下输入ar -crv libmyhello.a hello.o将创建静态库文件libmyhello。

xh@ubuntu:~/test1$ ar -crv libmyhello.a hello.o
a - hello.o

同样在终端运行ls命令查看结果

xh@ubuntu:~/test1$ ls
hello.c  hello.h  hello.o  libmyhello.a  main.c

(4)在程序中使用静态库

先生成目标程序hello,生成目标程序hello可有3种方式:
方法一:

xh@ubuntu:~/test1$ gcc -o hello main.c -L. -lmyhello

终端输入ls命令可以查看到目标程序hello已生成

xh@ubuntu:~/test1$ ls
hello  hello.c  hello.h  hello.o  libmyhello.a  main.c

自定义的库时,main.c还可放在-L.和-lmyhello之间,但是不能放在他俩之后,否则会提示myhello没定义。

方式二:
终端输入gcc main.c libmyhello.a -o hello

xh@ubuntu:~/test1$ gcc main.c libmyhello.a -o hello

方式三:
先在终端输入gcc -c main.c生成main.o;

xh@ubuntu:~/test1$ gcc -c main.c
xh@ubuntu:~/test1$ ls
hello  hello.c  hello.h  hello.o  libmyhello.a  main.c  main.o

再输入gcc -o hello mian.o libmyhello.a生成可执行文件。

xh@ubuntu:~/test1$ gcc -o hello main.o libmyhello.a

终端里输入./hello就可以运行hello程序;

xh@ubuntu:~/test1$ ./hello
Hello everyone!

我们删除静态文件试试公用函数hello是否真的连接到目标文件hello中了。

xh@ubuntu:~/test1$ rm libmyhello.a
xh@ubuntu:~/test1$ ls
hello  hello.c  hello.h  hello.o  main.c  main.o
xh@ubuntu:~/test1$ ./hello
Hello everyone!

由上可以看出,程序照常运行,静态库中的公用函数已经连接到目标文件中了。

(5)由.o文件创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件名扩展为.so。例如:我们将创建的动态库命名为myhello,则动态库文件名就是libmyhello.so。用gcc来创建动态库。
在系统命令提示符下输入gcc -shared -fPIC -o libmyhello.so hello.o得到动态库文件libmyhello.so;

xh@ubuntu:~/test1$ gcc -shared -fPIC -o libmyhello.so hello.o
/usr/bin/ld: hello.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
hello.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status

可以看到这里出现了错误,这时的解决方法是将前面的gcc -c hello.c换成gcc -fPIC -c hello.c;

xh@ubuntu:~/test1$ gcc -fPIC -c hello.c
xh@ubuntu:~/test1$ gcc -shared -fPIC -o libmyhello.so hello.o
xh@ubuntu:~/test1$ ls
hello  hello.c  hello.h  hello.o  libmyhello.so  main.c  main.o

由上述命令结果可知,这时再执行前面生成动态文件的命令将不会出错。

(6)在程序中使用动态库

先用gcc命令生成目标文件

xh@ubuntu:~/test1$ gcc -o hello main.c -L. -lmyhello

然后输入./hello运行程序。

xh@ubuntu:~/test1$ ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

哦!出错了。看看错误提示,原来是找不到动态文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则提示错误并终止程序运行。我们将文件libmyhello.so复制到目录/usr/lib中,再试试。

xh@ubuntu:~/test1$ mv libmyhello.so /usr/lib
mv: cannot move 'libmyhello.so' to '/usr/lib/libmyhello.so': Permission denied

可以看到又出现了问题,这时我们可以尝试在终端输入sudo su,输入密码,切换到root用户下,再输入cp libmyhello.so /usr/lib命令,将libmyhello.so复制到/usr/lib目录之下,最后输入./hello执行程序。

xh@ubuntu:~/test1$ sudo su
[sudo] password for xh: 
root@ubuntu:/home/xh/test1# cp libmyhello.so /usr/lib
root@ubuntu:/home/xh/test1# ./hello
Hello everyone!

可以看到,这时已经成功输出结果。
回过头来,我们可以发现使用静态库和动态库编译生成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?
首先我们先删除除.c和.h外的所有文件,利用rm 文件名命令来实现;

xh@ubuntu:~/test1$ rm libmyhello.so
xh@ubuntu:~/test1$ ls
hello.c  hello.h  main.c  main.o
xh@ubuntu:~/test1$ rm main.o
xh@ubuntu:~/test1$ ls
hello.c  hello.h  main.c

再来创建静态库文件libmyhello.a和动态文件libmyhello.so.

xh@ubuntu:~/test1$ ls
hello.c  hello.h  main.c
xh@ubuntu:~/test1$ gcc -fPIC -c hello.c
xh@ubuntu:~/test1$ ls
hello.c  hello.h  hello.o  main.c
xh@ubuntu:~/test1$ ar -cr libmyhello.a hello.o
xh@ubuntu:~/test1$ ls
hello.c  hello.h  hello.o  libmyhello.a  main.c
xh@ubuntu:~/test1$ gcc -shared -fPIC -o libmyhello.so hello.o
xh@ubuntu:~/test1$ ls
hello.c  hello.h  hello.o  libmyhello.a  libmyhello.so  main.c

接着,我们运行gcc命令来使用函数库myhello生成目录文件hello,并运行程序hello。

xh@ubuntu:~/test1$ gcc -o hello main.c -L. -lmyhello
xh@ubuntu:~/test1$ ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

可以看到上诉程序运行时有误,可以根据错误提示得出,当静态库和动态库同名时,gcc命令将优先使用动态库,默认去连/usr/lib/lib等目录的动态库,将文件libmyhello.so复制到目录/usr/lib中即可。

xh@ubuntu:~/test1$ gcc -o hello main.c -L. -lmyhello
xh@ubuntu:~/test1$ ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
xh@ubuntu:~/test1$ sudo su
root@ubuntu:/home/xh/test1# cp libmyhello.so /usr/lib
root@ubuntu:/home/xh/test1# exit
exit
xh@ubuntu:~/test1$ gcc -o hello main.c -L. -lmyhello
xh@ubuntu:~/test1$ ls
hello  hello.c  hello.h  hello.o  libmyhello.a  libmyhello.so  main.c
xh@ubuntu:~/test1$ ./hello
Hello everyone!

二、linux下静态库.a和.so库文件的生成和使用

首先创建一个目录

xh@ubuntu:~/test1$ mkdir test2
xh@ubuntu:~/test1$ cd test2

然后用vim、nano或gedit等文本编辑器编辑生成所需要的四个文件x2x.c、x2y.c、x2.h、main.c。

xh@ubuntu:~/test1/test2$ vim x2x.c
#include<stdio.h>
float x2x(int a,int b)
{
float sum;
sum=a+b;
print("a+b=%.2f\n",sum);
}
#include<stdio.h>
float x2y(int m,int n)
{
float mul;
mul=m*n;
printf("m*n=%.2f\n",mul);
}
#ifndef x2_H
#define x2_H
float x2x(int,int);
float x2y(int,int);
#endif
#include<stdio.h>
#include "x2.h"
int main()
{
x2x(3,4);
x2y(5,6);
exit(0);
}

(1)静态库.a文件的生成与使用

首先生成目标文件,即.o文件;

xh@ubuntu:~/test2$ gcc -c x2x.c x2y.c
xh@ubuntu:~/test2$ ls
main.c  x2.h  x2x.c  x2x.o  x2y.c  x2y.o

然后生成静态库.a文件;

xh@ubuntu:~/test2$ ar crv libafile.a x2x.o x2y.o
a - x2x.o
a - x2y.o
xh@ubuntu:~/test2$ ls
libafile.a  main.c  x2.h  x2x.c  x2x.o  x2y.c  x2y.o

使用.a文件,创建可执行程序;

root@ubuntu:/home/xh/test2# gcc -o main main.c libafile.a
root@ubuntu:/home/xh/test2# ./main
a+b=7.00
m*n=30.00

在终端命令行里输入ls -l main即可查看生成的目标程序main的大小。

root@ubuntu:/home/xh/test2# ls -l main
-rwxr-xr-x 1 root root 8720 Oct 16 17:02 main

(2)共享库.so文件的生成和使用

首先生成目标文件,即.o文件;

root@ubuntu:/home/xh/test2# gcc -c -fPIC x2x.c x2y.c

生成共享库.so文件;

xh@ubuntu:~/test2$ gcc -shared -fpic -o libsofile.so x2x.o x2y.o
xh@ubuntu:~/test2$ ls
libafile.a  libsofile.so  main  main.c  main.o  x2.h  x2x.c  x2x.o  x2y.c  x2y.o

使用.so库文件,创建可执行程序;

xh@ubuntu:~/test2$ gcc -o main main.c libsofile.so
xh@ubuntu:~/test2$ ./main
./main: error while loading shared libraries: libsofile.so: cannot open shared object file: No such file or directory

这里出现了错误,运行ldd main,查看情况;

xh@ubuntu:~/test2$ ldd main
	linux-vdso.so.1 =>  (0x00007fff83bdb000)
	libsofile.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0787635000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f07879ff000)

发现确实找不到.so文件。这是由于linux自身系统设定的原因,其只在/lib和/usr/lib下搜索对应的.so文件,只需将.so文件复制到其路径下即可;

xh@ubuntu:~/test2$ sudo su
[sudo] password for xh: 
root@ubuntu:/home/xh/test2# cp libsofile.so /usr/lib
root@ubuntu:/home/xh/test2# ./main
a+b=7.00
m*n=30.00

可以看到程序现在能正常运行了。
在终端命令行里输入ls -l main即可查看生成的目标程序main的大小。

root@ubuntu:/home/xh/test2# ls -l main
-rwxrwxr-x 1 xh xh 8624 Oct 16 17:29 main

将动态库生成的可执行程序和静态库相比较,发现动态库生成的可执行程序要小一些。

三、GCC常用命令

GCC即GNU C Compiler,GCC不仅支持C语言,它还支持Ada语言、C++语言、Java语言等。

(1)C语言程序编译

下面举一个C语言例子:

//test5.c
#include<stdio.h>
int main(void)
{
printf("Hello World!\n");
return 0;
}

这个程序一步到位的命令是gcc test5.c -o test5
实质上,上述编译过程是分四个阶段进行的,即预处理(也称为预编译)、编译、汇编和连接。

使用gcc -E test5.c -o test5.igcc -E test5.c进行预编译;

xh@ubuntu:~$ gcc -E test5.c -o test5.i
xh@ubuntu:~$ ls
a.out      Downloads         hello    main1.c   mian     Pictures  sub1.o     test1  test5    test.c
Desktop    examples.desktop  hello.c  main1.o   mkefile  Public    sub.c      test2  test5.c  Videos
Documents  func.h            main     makefile  Music    sub1.c    Templates  test3  test5.i

此时生成test5.i文件
预处理之后,可直接对生成的test5.i文件编译,生成汇编代码:

xh@ubuntu:~$ gcc -S test5.i -o test5.s
xh@ubuntu:~$ ls
a.out      Downloads         hello    main1.c   mian     Pictures  sub1.o     test1  test5    test5.s
Desktop    examples.desktop  hello.c  main1.o   mkefile  Public    sub.c      test2  test5.c  test.c
Documents  func.h            main     makefile  Music    sub1.c    Templates  test3  test5.i  Videos

gcc的-S选项,表示在程序编译期间,在生成汇编代码之后,停止,-o输出汇编代码文件。
将生产的汇编代码test5.s,用gas汇编器将其编译成目标文件:

xh@ubuntu:~$ gcc -c test5.s -o test5.o
xh@ubuntu:~$ ls
a.out      Downloads         hello    main1.c   mian     Pictures  sub1.o     test1  test5    test5.o  Videos
Desktop    examples.desktop  hello.c  main1.o   mkefile  Public    sub.c      test2  test5.c  test5.s
Documents  func.h            main     makefile  Music    sub1.c    Templates  test3  test5.i  test.c

gcc连接器是gas提供的,负责将程序中的目标文件与所需的所以附加文件的目标文件连接起来,最终生成可执行文件。

xh@ubuntu:~$ gcc test5.o -o test5
xh@ubuntu:~$ ls
a.out      Downloads         hello    main1.c   mian     Pictures  sub1.o     test1  test5    test5.o  Videos
Desktop    examples.desktop  hello.c  main1.o   mkefile  Public    sub.c      test2  test5.c  test5.s
Documents  func.h            main     makefile  Music    sub1.c    Templates  test3  test5.i  test.c

运行可执行文件。

xh@ubuntu:~$ ./test5
Hello World!

(2)多个程序文件的编译

假设有一个由test6.c和test7.c两个源文件组成的程序,为了对他们进行编译,并最终生成可执行程序test,可使用gcc test6.c test7.c -o test命令。

(3)检错

gcc -pedantic illcode.c -o illcode

-pedantic 编译选项并不能保证被编译程序与 ANSI/ISO C 标准的完全兼容,它仅仅只能用来帮助
Linux 程序员离这个目标越来越近。或者换句话说,-pedantic 选项能够帮助程序员发现一些不符合
ANSI/ISO C 标准的代码,但不是全部,事实上只有 ANSI/ISO C 语言标准中要求进行编译器诊断的
那些情况,才有可能被 GCC 发现并提出警告。

除了-pedantic 之外,GCC 还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W
开头,其中最有价值的当数-Wall 了,使用它能够使 GCC 产生尽可能多的警告信息。

gcc -Wall illcode.c -o illcode

GCC 给出的警告信息虽然从严格意义上说不能算作错误,但却很可能成为错误的栖身之所。一个优
秀的 Linux 程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮的特性。所以将
警告信息当成编码错误来对待,是一种值得赞扬的行为!所以,在编译程序时带上-Werror 选项,那
么 GCC 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:

gcc -Werror test.c -o test

(4)链接

静态库链接时搜索路径顺序:

  1. ld 会去找 GCC 命令中的参数-L
  2. 再找 gcc 的环境变量 LIBRARY_PATH
  3. 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初 compile gcc 时写在程序内的

动态链接时、执行时搜索路径顺序:

  1. 编译目标代码时指定的动态库搜索路径
  2. 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径
  3. 配置文件/etc/ld.so.conf 中指定的动态库搜索路径
  4. 默认的动态库搜索路径/lib
  5. 默认的动态库搜索路径/usr/lib

(5)ELF文件

1、ELF文件的段
ELF 文件位于 ELF Header 和 Section Header Table 之间的都
是段(Section)。一个典型的 ELF 文件包含下面几个段:
.text:已编译程序的指令代码段。
.rodata:ro 代表 read only,即只读数据(譬如常数 const)。
.data:已初始化的 C 程序全局变量和静态局部变量。
.bss:未初始化的 C 程序全局变量和静态局部变量。
.debug:调试符号表,调试器用此段的信息帮助调试。
可以使用 readelf -S 查看其各个 section 的信息如下:
在这里插入图片描述

xh@ubuntu:~$ readelf -S hello
There are 31 section headers, starting at offset 0x19d8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       000000000000001c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002b8  000002b8
       0000000000000060  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000400318  00000318
       000000000000003d  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400356  00000356
       0000000000000008  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400360  00000360
       0000000000000020  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000400380  00000380
       0000000000000018  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400398  00000398
       0000000000000030  0000000000000018  AI       5    24     8
  [11] .init             PROGBITS         00000000004003c8  000003c8
       000000000000001a  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000004003f0  000003f0
       0000000000000030  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         0000000000400420  00000420
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         0000000000400430  00000430
       0000000000000182  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         00000000004005b4  000005b4
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         00000000004005c0  000005c0
       0000000000000010  0000000000000000   A       0     0     4
  [17] .eh_frame_hdr     PROGBITS         00000000004005d0  000005d0
       0000000000000034  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000400608  00000608
       00000000000000f4  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000028  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000601028  00001028
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000601038  00001038
       0000000000000008  0000000000000000  WA       0     0     1
  [27] .comment          PROGBITS         0000000000000000  00001038
       0000000000000035  0000000000000001  MS       0     0     1
  [28] .shstrtab         STRTAB           0000000000000000  000018cc
       000000000000010c  0000000000000000           0     0     1
  [29] .symtab           SYMTAB           0000000000000000  00001070
       0000000000000648  0000000000000018          30    47     8
  [30] .strtab           STRTAB           0000000000000000  000016b8
       0000000000000214  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

2、反编译ELF
由于 ELF 文件无法被当做普通文本文件打开,如果希望直接查看一个 ELF 文件包
含的指令和数据,需要使用反汇编的方法。
使用 objdump -D 对其进行反汇编如下:

xh@ubuntu:~$ objdump -S hello

hello:     file format elf64-x86-64


Disassembly of section .init:

00000000004003c8 <_init>:
  4003c8:	48 83 ec 08          	sub    $0x8,%rsp
  4003cc:	48 8b 05 25 0c 20 00 	mov    0x200c25(%rip),%rax        # 600ff8 <_DYNAMIC+0x1d0>
  4003d3:	48 85 c0             	test   %rax,%rax
  4003d6:	74 05                	je     4003dd <_init+0x15>
  4003d8:	e8 43 00 00 00       	callq  400420 <__libc_start_main@plt+0x10>
  4003dd:	48 83 c4 08          	add    $0x8,%rsp
  4003e1:	c3                   	retq   

Disassembly of section .plt:

00000000004003f0 <puts@plt-0x10>:
  4003f0:	ff 35 12 0c 20 00    	pushq  0x200c12(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003f6:	ff 25 14 0c 20 00    	jmpq   *0x200c14(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003fc:	0f 1f 40 00          	nopl   0x0(%rax)

0000000000400400 <puts@plt>:
  400400:	ff 25 12 0c 20 00    	jmpq   *0x200c12(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  400406:	68 00 00 00 00       	pushq  $0x0
  40040b:	e9 e0 ff ff ff       	jmpq   4003f0 <_init+0x28>

0000000000400410 <__libc_start_main@plt>:
  400410:	ff 25 0a 0c 20 00    	jmpq   *0x200c0a(%rip)        # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  400416:	68 01 00 00 00       	pushq  $0x1
  40041b:	e9 d0 ff ff ff       	jmpq   4003f0 <_init+0x28>

Disassembly of section .plt.got:

0000000000400420 <.plt.got>:
  400420:	ff 25 d2 0b 20 00    	jmpq   *0x200bd2(%rip)        # 600ff8 <_DYNAMIC+0x1d0>
  400426:	66 90                	xchg   %ax,%ax

Disassembly of section .text:

0000000000400430 <_start>:
  400430:	31 ed                	xor    %ebp,%ebp
  400432:	49 89 d1             	mov    %rdx,%r9
  400435:	5e                   	pop    %rsi
  400436:	48 89 e2             	mov    %rsp,%rdx
  400439:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
  40043d:	50                   	push   %rax
  40043e:	54                   	push   %rsp
  40043f:	49 c7 c0 b0 05 40 00 	mov    $0x4005b0,%r8
  400446:	48 c7 c1 40 05 40 00 	mov    $0x400540,%rcx
  40044d:	48 c7 c7 26 05 40 00 	mov    $0x400526,%rdi
  400454:	e8 b7 ff ff ff       	callq  400410 <__libc_start_main@plt>
  400459:	f4                   	hlt    
  40045a:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)

0000000000400460 <deregister_tm_clones>:
  400460:	b8 3f 10 60 00       	mov    $0x60103f,%eax
  400465:	55                   	push   %rbp
  400466:	48 2d 38 10 60 00    	sub    $0x601038,%rax
  40046c:	48 83 f8 0e          	cmp    $0xe,%rax
  400470:	48 89 e5             	mov    %rsp,%rbp
  400473:	76 1b                	jbe    400490 <deregister_tm_clones+0x30>
  400475:	b8 00 00 00 00       	mov    $0x0,%eax
  40047a:	48 85 c0             	test   %rax,%rax
  40047d:	74 11                	je     400490 <deregister_tm_clones+0x30>
  40047f:	5d                   	pop    %rbp
  400480:	bf 38 10 60 00       	mov    $0x601038,%edi
  400485:	ff e0                	jmpq   *%rax
  400487:	66 0f 1f 84 00 00 00 	nopw   0x0(%rax,%rax,1)
  40048e:	00 00 
  400490:	5d                   	pop    %rbp
  400491:	c3                   	retq   
  400492:	0f 1f 40 00          	nopl   0x0(%rax)
  400496:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  40049d:	00 00 00 

00000000004004a0 <register_tm_clones>:
  4004a0:	be 38 10 60 00       	mov    $0x601038,%esi
  4004a5:	55                   	push   %rbp
  4004a6:	48 81 ee 38 10 60 00 	sub    $0x601038,%rsi
  4004ad:	48 c1 fe 03          	sar    $0x3,%rsi
  4004b1:	48 89 e5             	mov    %rsp,%rbp
  4004b4:	48 89 f0             	mov    %rsi,%rax
  4004b7:	48 c1 e8 3f          	shr    $0x3f,%rax
  4004bb:	48 01 c6             	add    %rax,%rsi
  4004be:	48 d1 fe             	sar    %rsi
  4004c1:	74 15                	je     4004d8 <register_tm_clones+0x38>
  4004c3:	b8 00 00 00 00       	mov    $0x0,%eax
  4004c8:	48 85 c0             	test   %rax,%rax
  4004cb:	74 0b                	je     4004d8 <register_tm_clones+0x38>
  4004cd:	5d                   	pop    %rbp
  4004ce:	bf 38 10 60 00       	mov    $0x601038,%edi
  4004d3:	ff e0                	jmpq   *%rax
  4004d5:	0f 1f 00             	nopl   (%rax)
  4004d8:	5d                   	pop    %rbp
  4004d9:	c3                   	retq   
  4004da:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)

00000000004004e0 <__do_global_dtors_aux>:
  4004e0:	80 3d 51 0b 20 00 00 	cmpb   $0x0,0x200b51(%rip)        # 601038 <__TMC_END__>
  4004e7:	75 11                	jne    4004fa <__do_global_dtors_aux+0x1a>
  4004e9:	55                   	push   %rbp
  4004ea:	48 89 e5             	mov    %rsp,%rbp
  4004ed:	e8 6e ff ff ff       	callq  400460 <deregister_tm_clones>
  4004f2:	5d                   	pop    %rbp
  4004f3:	c6 05 3e 0b 20 00 01 	movb   $0x1,0x200b3e(%rip)        # 601038 <__TMC_END__>
  4004fa:	f3 c3                	repz retq 
  4004fc:	0f 1f 40 00          	nopl   0x0(%rax)

0000000000400500 <frame_dummy>:
  400500:	bf 20 0e 60 00       	mov    $0x600e20,%edi
  400505:	48 83 3f 00          	cmpq   $0x0,(%rdi)
  400509:	75 05                	jne    400510 <frame_dummy+0x10>
  40050b:	eb 93                	jmp    4004a0 <register_tm_clones>
  40050d:	0f 1f 00             	nopl   (%rax)
  400510:	b8 00 00 00 00       	mov    $0x0,%eax
  400515:	48 85 c0             	test   %rax,%rax
  400518:	74 f1                	je     40050b <frame_dummy+0xb>
  40051a:	55                   	push   %rbp
  40051b:	48 89 e5             	mov    %rsp,%rbp
  40051e:	ff d0                	callq  *%rax
  400520:	5d                   	pop    %rbp
  400521:	e9 7a ff ff ff       	jmpq   4004a0 <register_tm_clones>

0000000000400526 <main>:
  400526:	55                   	push   %rbp
  400527:	48 89 e5             	mov    %rsp,%rbp
  40052a:	bf c4 05 40 00       	mov    $0x4005c4,%edi
  40052f:	e8 cc fe ff ff       	callq  400400 <puts@plt>
  400534:	b8 00 00 00 00       	mov    $0x0,%eax
  400539:	5d                   	pop    %rbp
  40053a:	c3                   	retq   
  40053b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

0000000000400540 <__libc_csu_init>:
  400540:	41 57                	push   %r15
  400542:	41 56                	push   %r14
  400544:	41 89 ff             	mov    %edi,%r15d
  400547:	41 55                	push   %r13
  400549:	41 54                	push   %r12
  40054b:	4c 8d 25 be 08 20 00 	lea    0x2008be(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400552:	55                   	push   %rbp
  400553:	48 8d 2d be 08 20 00 	lea    0x2008be(%rip),%rbp        # 600e18 <__init_array_end>
  40055a:	53                   	push   %rbx
  40055b:	49 89 f6             	mov    %rsi,%r14
  40055e:	49 89 d5             	mov    %rdx,%r13
  400561:	4c 29 e5             	sub    %r12,%rbp
  400564:	48 83 ec 08          	sub    $0x8,%rsp
  400568:	48 c1 fd 03          	sar    $0x3,%rbp
  40056c:	e8 57 fe ff ff       	callq  4003c8 <_init>
  400571:	48 85 ed             	test   %rbp,%rbp
  400574:	74 20                	je     400596 <__libc_csu_init+0x56>
  400576:	31 db                	xor    %ebx,%ebx
  400578:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)
  40057f:	00 
  400580:	4c 89 ea             	mov    %r13,%rdx
  400583:	4c 89 f6             	mov    %r14,%rsi
  400586:	44 89 ff             	mov    %r15d,%edi
  400589:	41 ff 14 dc          	callq  *(%r12,%rbx,8)
  40058d:	48 83 c3 01          	add    $0x1,%rbx
  400591:	48 39 eb             	cmp    %rbp,%rbx
  400594:	75 ea                	jne    400580 <__libc_csu_init+0x40>
  400596:	48 83 c4 08          	add    $0x8,%rsp
  40059a:	5b                   	pop    %rbx
  40059b:	5d                   	pop    %rbp
  40059c:	41 5c                	pop    %r12
  40059e:	41 5d                	pop    %r13
  4005a0:	41 5e                	pop    %r14
  4005a2:	41 5f                	pop    %r15
  4005a4:	c3                   	retq   
  4005a5:	90                   	nop
  4005a6:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  4005ad:	00 00 00 

00000000004005b0 <__libc_csu_fini>:
  4005b0:	f3 c3                	repz retq 

Disassembly of section .fini:

00000000004005b4 <_fini>:
  4005b4:	48 83 ec 08          	sub    $0x8,%rsp
  4005b8:	48 83 c4 08          	add    $0x8,%rsp
  4005bc:	c3                   	retq   

(6)使用nasm汇编编译器编译hello.asm

在终端命令行内输入sudo apt-get install nasm安装nasm编译器。
编写一个hello.asm代码:

section .data            ; 数据段声明
        msg db "Hello, world!", 0xA     ; 要输出的字符串
        len equ $ - msg                 ; 字串长度
section .text            ; 代码段声明
global _start            ; 指定入口函数
_start:                  ; 在屏幕上显示一个字符串
        mov edx, len     ; 参数三:字符串长度
        mov ecx, msg     ; 参数二:要显示的字符串
        mov ebx, 1       ; 参数一:文件描述符(stdout) 
        mov eax, 4       ; 系统调用号(sys_write) 
        int 0x80         ; 调用内核功能
                         ; 退出程序
        mov ebx, 0       ; 参数一:退出代码
        mov eax, 1       ; 系统调用号(sys_exit) 
        int 0x80         ; 调用内核功能

使用nasm -f win64 hello.asm命令进行编译;
进而生成可执行程序进行运行;

xh@ubuntu:~$ touch hello.asm
xh@ubuntu:~$ gedit hello.asm
xh@ubuntu:~$ nasm -f elf64 hello.asm
xh@ubuntu:~$ ld -s -o hello hello.o
xh@ubuntu:~$ ./hello
Hello, world!

利用size+文件名即可查看其文件大小。

xh@ubuntu:~$ size hello
   text	   data	    bss	    dec	    hex	filename
     34	     14	      0	     48	     30	hello

再查看c代码里面编译生成的目标程序的大小:

xh@ubuntu:~$ size hello
   text	   data	    bss	    dec	    hex	filename
   1182	    552	      8	   1742	    6ce	hello

可以发现用nasm汇编编译器生成的目标文件更节省空间。

四、第三方库函数curses

curses 函数库的名称来自它所提供的功能,它能够优化光标的移动并减少需要对屏幕进行的刷新,减少了必须向字符终端发送的字符数目。

当对使用curse函数库的程序进行编译时,必须在程序中包含头文件curses.h,需要在命令行中用-lcurses选项对curses函数库进行链接,所有的curses程序必须从初始函数initscr开始,以函数endwin结束。函数initscr在一个程序中只能调用一次。

在 win10 系统中,“控制面板”–>“程序”—>“启用或关闭Windows功能”,启用 “telnet client” 和"适用于Linux的Windows子系统"(后面会使用)。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,以游客身份体验一下即将绝迹的远古时代的 BBS (一个用键盘光标控制的终端程序)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在ubuntu中安装cueses库,需要用到sudo apt-get install libncurses5-dev命令。安装完成后我们可以用find / -name curses.h命令查看头文件和库文件所在的目录:

xh@ubuntu:~$ sudo su
root@ubuntu:/home/xh# find / -name curses.h
/usr/include/curses.h
find: ‘/run/user/1000/gvfs’: Permission denied
xh@ubuntu:~$ find / -name term.h
find: ‘/etc/cups/ssl’: Permission denied
find: ‘/etc/ssl/private’: Permission denied
find: ‘/etc/polkit-1/localauthority’: Permission denied
find: ‘/proc/tty/driver’: Permission denied
find: ‘/proc/1/task/1/fd’: Permission denied
find: ‘/proc/1/task/1/fdinfo’: Permission denied
find: ‘/proc/1/task/1/ns’: Permission denied
find: ‘/proc/1/fd’: Permission denied
find: ‘/proc/1/map_files’: Permission denied
find: ‘/proc/1/fdinfo’: Permission denied
find: ‘/proc/1/ns’: Permission denied
find: ‘/proc/2/task/2/fd’: Permission denied
find: ‘/proc/2/task/2/fdinfo’: Permission denied
/usr/include/term.h

有许多目录因为权限的原因无法遍历。
那么我们可以换一下试试,用whereis代替find:

xh@ubuntu:~$ whereis / -name curses.h
: /usr/bin/. /usr/sbin/. /usr/lib/. /bin/. /sbin/. /etc/. /lib/. /lib64/. /usr/games/. /usr/local/bin/. /usr/local/sbin/. /usr/local/etc/. /usr/local/lib/. /usr/local/games/. /usr/include/. /usr/local/. /usr/libexec/. /usr/share/. /usr/share/man/hy/. /usr/share/man/bs/. /usr/share/man/cy/. /usr/share/man/shn/. /usr/share/man/sl/. /usr/share/man/nb/. /usr/share/man/ms/. /usr/share/man/kk/. /usr/share/man/man2/. /usr/share/man/ps/. /usr/share/man/man9/. /usr/share/man/fr.ISO8859-1/. /usr/share/man/fr_CA/. /usr/share/man/man8/. /usr/share/man/si/. /usr/share/man/pl/. /usr/share/man/eo/. /usr/share/man/el/. /usr/share/man/uk/. /usr/share/man/my/. /usr/share/man/ku/. /usr/share/man/bg/. /usr/share/man/lt/. /usr/share/man/ro/. /usr/share/man/tr/. /usr/share/man/sq/. /usr/share/man/zh_HK/. /usr/share/man/man4/. /usr/share/man/io/. /usr/share/man/man1/. /usr/share/man/es/. /usr/share/man/et/. /usr/share/man/fo/. /usr/share/man/ta/. /usr/share/man/hu/. /usr/share/man/ne/. /usr/share/man/gl/. /usr/share/man/eu/. /usr/share/man/gd/. /usr/share/man/zh_TW/. /usr/share/man/pt_BR/. /usr/share/man/fa/. /usr/share/man/it/. /usr/share/man/hi/. /usr/share/man/pa/. /usr/share/man/ce/. /usr/share/man/lv/. /usr/share/man/sv/. /usr/share/man/ca/. /usr/share/man/man3/. /usr/share/man/fy/. /usr/share/man/se/. /usr/share/man/he/. /usr/share/man/bn/. /usr/share/man/sr/. /usr/share/man/ug/. /usr/share/man/uz/. /usr/share/man/man7/. /usr/share/man/bo/. /usr/share/man/ru/. /usr/share/man/en_GB/. /usr/share/man/fr.UTF-8/. /usr/share/man/id/. /usr/share/man/pt/. /usr/share/man/az/. /usr/share/man/th/. /usr/share/man/ar/. /usr/share/man/man5/. /usr/share/man/ca@valencia/. /usr/share/man/en_CA/. /usr/share/man/cs/. /usr/share/man/ko/. /usr/share/man/vi/. /usr/share/man/oc/. /usr/share/man/fi/. /usr/share/man/mhr/. /usr/share/man/de/. /usr/share/man/nn/. /usr/share/man/zh_CN/. /usr/share/man/ast/. /usr/share/man/hr/. /usr/share/man/sk/. /usr/share/man/fr/. /usr/share/man/km/. /usr/share/man/te/. /usr/share/man/nl/. /usr/share/man/en_AU/. /usr/share/man/ml/. /usr/share/man/da/. /usr/share/man/be/. /usr/share/man/man6/. /usr/share/man/ja/. /usr/share/info/. /usr/src/linux-headers-4.15.0-120-generic/.tmp_versions /usr/src/linux-headers-4.15.0-120-generic/.config /usr/src/linux-headers-4.15.0-120-generic/. /usr/src/linux-headers-4.15.0-112-generic/.tmp_versions /usr/src/linux-headers-4.15.0-112-generic/.config /usr/src/linux-headers-4.15.0-112-generic/. /usr/src/linux-headers-4.15.0-112/. /usr/src/linux-headers-4.15.0-120/.

可以看到,whereis可以访问。

用C语言编写一个贪吃蛇游戏

完整代码:http://www.linuxidc.com/Linux/2011-08/41375.htm
将代码在linux ubuntu中写入.c文件,在终端输入gcc snake.c -lcurses -o snake命令生成目标可执行程序;
最后输入./snake即可运行。
在这里插入图片描述

在这里插入图片描述

总结:gcc编译器使用广泛,命令也比较多样,静态库和动态库在linux里面都是比较重要的一个概念,关于curses应用比较复杂,要想搞懂,还需要多费一些时间。在编写命令过程中也是在不断尝试,遇到报错也不要慌,遇到了就是赚到,这次想办法解决了,下次就能轻松解决。

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值