《Linux高级程序设计》读书笔记1

第一章     Linux简介

    介绍比较广泛,基本上每一本讲编程的书上都会提到的一些泛泛的概念,有几个单词/概念强化一下比较好。

    FLOSS: Free/Libre/Open Source Software, libre是法语里革命的意思。翻译成中文是自由/开放源码软件。

    www.distrowatch.com  可用于跟踪现代Linux发行版的当前发展趋势。

    自动化发行版构建工具PTXdist: http://ptxdist.fs.net

    /etc/sudoes下列举的普通用户帐户规定了哪些用户可以使用sudo命令,修改它

# User privilege specification root    
ALL=(ALL) ALL dash   ALL=(ALL)ALL

    沙盒和虚拟化技术: VMware(http://www.vmware.com), Qemu,Xen

    Linux三大特点: 模块化、可移植的、通用的。

 

第二章     工具链

2.1 Linux开发过程

    第一步要做的是得到源代码,有两种方法可以得到源代码:第一种方式是源代码打包工具(tarball文件),tar.gz/tar.bz2,第二种方法是通过SCM工具取得源码。

    之后是配置本地环境,通过configure来进行。源码包的顶层目录里的README和INSTALL文件描述了重新编译软件的标准过程。配置本地编译 环境非常必要,因为Linux可以运行于不同的平台上,每个不同的硬件环境都有可能有其特定的限制。例如字节序问题、可执行程序的格式问题、各自不同的软 件环境问题等。Autoconf是用来描述这些差别的一套工具,通过生成的configure脚本来体现其功能。

    configure脚本将自动判断你是否安装了必需的GNU工具,并通过实际编译一个非常简单的test程序来验证它们是否可以正常工作。

   configure通过后会生成Makefile文件,make后得到可执行文件,makefile里会有不同规则对应不同动作。

 

2.2 GNU toolchain 的组成

    应当尽可能地简化Linux软件的编译过程,很多根本不存在的bug只是因为编译过程过于复杂而产生的副作用。要了解这些工具的大概用法,但是不要太过于依赖它们。

    GCC诞生于1987年,现在已经有了多种语言支持版,如c,c++,Ada, Fortran, Objective C, java等。支持多种平台,例如Intel IA32(X86), AMD64-Bit Processor, ARM, SPARC, PowerPC.

   单个文件的编译(gcc -o), 多个文件的编译(gcc -c, gcc -o)

 

   有关GLIBC

   C语言设计上的一个副作用:C语言过于简单,所以太多的功能都不放在语言本身来实现。甚至连一些基本的任务,如I/O, 读写文件和终端显示窗口都要借助于外部库例程来执行。

   而在Linux环境下,几乎每一个Linux应用程序都要依赖于由GNU函数库GLIBC提供的例程。基本的I/O等提供者就是它。不论你是否明确地调用它,像exit()这样的函数都会被调用。exit函数用于请求内核正常终止程序。

    GNU C函数库构成Linux内核上的一个薄层并提供了许多有用的例程,如果这些例程都由内核来提供的话,付出的代价将相当昂贵(根据代码效率和增加的复杂 性)。事实上,在你要求GCC执行编译任务时,GCC在默认情况下将假设GLIBC将被包括进你的程序。由于这一过程发生在连接阶段,所以还需要在应用程 序源代码中添加库函数的头文件以提供给库函数自身的原型定义。

    很少情况下,我们才不会在编译源代码的时候使用GLIBC,我们也的确可以这样做。例如Linux内核就完全没有使用GLIBC,而是在内核中包含了它自 己对许多标准C库函数的简化实现,这是因为GLIBC依赖于Linux内核来代表它执行多种服务(我觉得最后一句翻译过来有疑问!!!)

 

    链接到某个库 gcc -o *** -lm ***.c  链接到数学库(libm)。真正的库函数位置随系统的不同而不同,但它一般位于目录/lib或/usr/lib中。

 

    共享函数库/静态函数库

    静态函数库继承于往昔的UNIX系统,那时所有的软件库都静态连接到使用这些库中例程的代码。每次当应用程序和静态连接的函数库一起编译时,任何引用的库例程中的代码都会被直接包含进最终的二进制程序。每个可执行程序都将包含标准例程的副本,所以它的容量较大。

    共享函数库里的例程并不是直接插入每个要连接它的程序。相反,共享函数库包含每个库函数的单一全局版本,它在所有应用程序之间被共享。主要依赖的机制是现代计算机的虚拟内存能力,它允许包含库例程的物理内存安全地在多个独立用户程序之间共享。

    共享函数库的好处:减少了文件的容量和Linux应用程序在内存中覆盖的区域,还提高了系统的安全性。如果安全问题出现在共享资源库中,则可以在不对软件进行重新编译的情况下保证它是最新的,因为只需要一个全局的函数库就能自动修复应用程序。

    另一个好处是:一个被许多不同程序同时调用的共享函数库很可能会驻留在内存中,以在需要使用它的时候被立即使用,而不是位于磁盘的交换分区中。有助于进一步减少一些大型Linux应用程序的装载时间。

 

    位置无关

    gcc -fPIC -c *.c

    共享软件库的建立: gcc -shared -o libmessage.so message.o

    gcc -o *** -lmessage -L. main.o

    -L. 表示函数库可能位于当前目录(包含程序源文件的目录)。

 

    自己建立的任何共享函数库可以像Linux系统上安装的其他函数库一样使用,但是它必须被安装到正确的位置以使得这样的使用完全自动化。当有使用共享函数 库的应用程序被加载时,现代Linux所提供的运行时动态连接器/加载器-ld-linux会被自动调用并在标准系统目录/lib 和/usr/lib(/etc/ld.so.conf可以用来修改)下查找函数库。发布应用程序时,需要在软件安装过程中将一些必需的函数库安装到系统可 以在运行时自动搜索到的目录中。根据系统具体情况的不同,还可能再次需要运行命令ldconfig.

    ldd可以用来发现一个特定应用程序需要的函数库。ldd - print shared library dependencies

 

GCC选项

    一般选项: 指定GCC产生的可执行文件名/是否需要GCC完成整个编译过程/完成基本编译之后终止。-s/-c

    语言选项: 允许控制GCC对当前源文件所使用的编程语言相关标准的解释。-ansi

    警告级别: 提供多种警告级别,帮助追查某些类型的不良编程习惯。-Wall

    调试:用于方便对应用程序调试的各种选项。 -g

    优化: 对编译的代码执行各种优化。 -os

    硬件选项: 支持不同的硬件目标,涉及到交叉编译的情形。-march -msoft-float -mbig-endian -mlittle-endian -mabi 很多开发人员会使用GCC的硬件选项标记来改变默认的处理器目标或设置特定于他们本地CPU模型的其他选项。会让本地编译的应用程序得到最大程度的性能提 高,但是可移植性差。

    更详细的文档:  man gcc /info gcc

 

2.3 GNU 二进制工具集

    GNU GCC依赖于一些外部工具来实际代表Linux开发者来执行有用的工作。这些工作由GNU的二进制工具集来提供。工具的集合,用于产生和控制Linux中的二进制应用程序代码。

    GNU as:负责把已经编译的C代码转换为能在某一特定目标处理器上执行的目标代码。如: gcc -S hello.c / as -o hello.o hello.s

    GNU ld:源代码首先被编译、汇编后,然后被连接到一个被目标Linux系统理解的标准容器格式(standard container format)。ELF(Executable & Linking Format, 可执行和连接格式)。由各种段落组成,程序自身的代码段和数据段以及各种和应用程序本身相关的元数据。连接阶段保证可执行文件中包含足够多的额外数据以使 得Linux运行时装载器可以成功地装载并执行该程序。crtbegin.o crtend.o    /usr/lib/gcc/i486-linux-gnu/4.1.2/crtbegin.o

    /usr/lib/ldscripts下有连接器脚本的预编写命令,当ld需要创建一个特定类型的Linux可执行文件时,就会使用其中的脚本。

    GNU objcopy: 可以用于从一个文件拷贝目标代码到另一个文件,并在这一过程中执行各种转换。使用它可以在不同的目标代码格式之间进行自动的转换并操作这一过程中的内容。建立在bfd二进制操纵函数库上。

    GNU objdump用来方便查看可执行文件的内容,并通过执行各种任务使得这一可视化过程更加容易。

    objdump objdump -x -d -S hello

 
0804834c <main>:
#include <stdio.h>
int main(void)
{
 804834c:       55                      push   %ebp
 804834d:       89 e5                   mov    %esp,%ebp
 804834f:       83 ec 08                sub    $0x8,%esp
 8048352:       83 e4 f0                and    $0xfffffff0,%esp
 8048355:       b8 00 00 00 00          mov    $0x0,%eax
 804835a:       83 c0 0f                add    $0xf,%eax
 804835d:       83 c0 0f                add    $0xf,%eax
 8048360:       c1 e8 04                shr    $0x4,%eax
 8048363:       c1 e0 04                shl    $0x4,%eax
 8048366:       29 c4                   sub    %eax,%esp
        printf("Hello World! \n");
 8048368:       c7 04 24 3c 84 04 08    movl   $0x804843c,(%esp)
 804836f:       e8 44 ff ff ff          call   80482b8 <printf@plt>
        return 0;
 8048374:       b8 00 00 00 00          mov    $0x0,%eax

}
 

     GNU Make: 去看《GNU Makefile入门》那本书吧,欧莱丽的。 $(CC) $(CFLAGS)的扩展。学习它的最好的方法是下载一个大型的自由软件项目的源代码,通过阅读它所使用的Makefile文件,将很快弄清楚make的规则集。Linker and Loader(Morgan Kaufman 2000),关于ELF文件格式的设计和实现以及标准工具例如GNU连接器操作的内容。

    GNU GDB: GDB里很多概念大多都是操作性的。

    list: 查看调试会话中的一部分源代码。

    run: 命令可以运行该需要调试的程序。

    break: 插入一个断点。习惯是break main,在main函数的入口处插入第一个程序断点。

    next: 下一条运行语句。

    print: 查看变量的值

    continue(c): 让程序继续运行

    help: 打印出帮助消息

    另一个用途是用来调试程序的核心转储(core dump)

 

2.6 Linux内核和GNU工具链

    Linux内核极度依赖于GCC中许多语言扩展以及其他常用系统工具的GNU扩展。

 

2.6.1 内联汇编

    底层Linux内核代码会经常使用GNU C编译器的一个扩展以支持内联汇编代码。有些指令只能用机器特定的指令来执行,所以,内联汇编相当有意义。

void write_reg32(unsigned long address, unsigned long data) {      __asm__ __volatile ("stw %0, 0(%1); eieio"                                        : //no output registers here                                        : "r" (data), "r"(address)); }

    __volatile不要试图优化代码。__asm__后面是PowerPC汇编语言。之需要关注内联汇编的格式调用问题,这样我们可以在Linux内核源码中找到更多的内联汇编的例子。

 

2.6.2 属性标记

 

2.6.3 定制连接器脚本

 

2.7 交叉编译

configure脚本时的选项:

--build      配置为指定的主机类型进行编译

--host      交叉编译运行于指定主机类型上的程序。

 

2.8建立GNU编译链

参考LFS手册

http://kegel.com/crosstool 来获得crosstool 使得自动下载单个工具链源代码的过程变得自动化,并自动地为期待的目标组合打补丁,然后正确编译,结束时可以运行标准的回归测试。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值