20145214 《信息安全系统设计基础》第2周学习总结

教材学习内容总结

通过VIMTUTOR实践教程了解VIM编辑器

  • h:左移 j:下移 k:上移 l:右移

  • :q!:退出编辑器,放弃所有改动

  • x:删除光标所在位置的字符

  • i:在光标前插入文本字符

  • A:在一行后添加文本

  • :wq:保存文件并退出

  • vim 文件名:进入编辑器

  • dw:从光标处删除至一个单词的末尾

  • d$:从当前光标删除至行末

  • de:从当前光标删除至单词末尾

  • d 数字 w:删除数字个大写字母单词

  • dd:删除该行 2dd:删除两行

  • u:撤销最后执行的命令 U:撤销对整行的修改

  • CTRL + R:恢复以前的操作结果

  • p:将最后一次删除的内容置入光标之后

  • r + 字符:替换光标所在位置的字符

  • cw:改变文本直到一个单词的末尾

  • c$:从光标处开始删除至行末

gcc编译器的基本原理

  • gcc 编译流程解析:预处理、编译、汇编、链接

  • Linux的可执行文件并没有像 Windows 那样有明显的.exe后缀名, 只需向其分配x(可执行)权限即可 sudo chmod u+x excutefile

  • gcc的-E参数可以让gcc在预处理结束后停止编译过程

  • gcc预处理源文件的时候(第一步),不会进行语法错误的检查。语法检查会在第二步进行,比如花括号不匹配、行末尾没有分号、关键字错误等

    1)预处理阶段:在该阶段,对包含的头文件(#include)和宏定义(#define、#ifdef 等)进行处理。在上述代码的预处理过 程中,编译器将包含的头文件 stdio.h 编译进来,并且用户可以使用 gcc 的选项“-E”进行查看,该选项的 作用是让 gcc 在预处理结束后停止编译过程。

    gcc –E hello.c –o hello.i

    选项“-o”是指目标文件,“.i”文件为已经过􏰄处理的 C 程序。
    (gcc 指令的一般格式为:gcc [选项] 要编译的文件 [选项] [目标文件] 其中,目标文件可缺省,gcc 默认生成可执行的文件,名为:编译文件.out)

    2)编译阶段:接下来进行的是编译阶段,在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。用户可以使用“-S”选项来进行查看, 该选项只进行编译而不进行汇编,结果生成汇编代码。

    gcc –S hello.i –o hello.s

    3)汇编阶段:汇编阶段是把编译阶段生成的“.s”文件转成目标文件,读者在此使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。

    gcc –c hello.s –o hello.o

    4)链接阶段:在成功编译之后,就进入了链接阶段。 系统把函数的实现都放到名为 libc.so.6 的库文件中去了,在没有特别指定时, gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 􏰃数库中去,这样就能􏰇使用各类函数了,而这也正是链接的作用。

    函数库有静态库和动态库两种。静态库是指编译链接时,将库文件的代码全部加入可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后名通常为“.a”。动态库与之相反,在编译链接时并没有将库文件的代码加入可执行文件中,而是在程序执行时加载库,这样可以节省系统的开销。一般动态库的后􏰉名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。 完成了链接之后,gcc 就可以生成可执行文件。

    gcc hello.o –o hello

    ./hello

  • 用gcc编译一个经典的c程序

  • gcc编译模块化的程序

gcc编译中的库选项

  • 我们所编写的.c文件都可以制作一个􏰃函数库。过程如下:

  • a.静态库的创建和使用:使用归档工具ar将一些目标文件集成在一起。例如:

     [root@localhost lib]# `gcc -c haha.c`
     [root@localhost lib]# `ar rcsv libpow.a haha.o`
     a - haha.o
    

下面编译主程序,它将会链接到刚生成的静态库haha.a:

	[root@localhost lib]# `gcc -o heihei heihei.c -L. -lpow`
	[root@localhost lib]# `./heihei 2 10`
	2^10=1024

其中,选项“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加 dir 目录,而“-lname” 选项指示编译时链接到库文件 libname.a 或者 libname.so。本实例中,程序heihei.c 需要使用当前目录下的一个静􏰈态库 libpow.a。

  • b.动态库(共享库)的创建和使用:首先使用gcc的-fPIC选项为动态库创造一个目标文件:

      [root@localhost lib]# `gcc -fPIC -Wall -c haha.c`
    

接下来使用-shared选项和已创建的位置无关目标代码,生成一个动态库libpow.so

	[root@localhost lib]#  `gcc -shared -o libpow.so haha.o`

下面编译主程序,它将会链接到刚生成的动态库libpow.so

        [root@localhost lib]# `gcc -o heihei heihei.c -L. -lpow`
  • 在运行可执行程序之前,需要注册动态库的路径名。其方法有几种:修改/etc/ld.so.conf 文件,或者修改 LD_LIBRARY_PATH 环境􏰦变量,或者将库文件直接复制到/lib 或者/usr/lib 目录下(这两个目录为系统的默认的库路径名)。

      [root@localhost lib]# `op libpow.so /lib`
      [root@localhost lib]# `./heihei 2 10
      2^10=1024
    
  • 动态库只有当使用它的程序执行时才被链接使用,而不是将需要的部分直接编入可执行文件中,并且一 个动态库可以被多个程序使用故可称为共享库,而静态库将会整合到程序中,因此在程序执行时不用加载静态库。 从而可知,链接到静态库会使用户的程序,并且难以升级,但是可能会比较容易部署。而链接到动态库会使用户的程序轻便,并且易于升级,但是会难以部署

gdb调试技术

  • gdb主要帮忙用户完成下面4个方面的功能:

    1.启动程序,可以按照用户自定义的要求随心所欲的运行程序。
    2.可让被调试的程序在用户所指定的调试的断点处停住 (断点可以是条件表达式)。
    3.当程序停住时,可以检查此时程序中所发生的事。
    4.动态地改变程序的执行环境。
    5.从上面来看,gdb和一般的调试工具区别不大,基本上也是完成这些功能,不过在细节上,会发现gdb这个调试工具的强大。大家可能习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。
    
  • 启动gdb的方法有以下几种:

     1.gdb <program> program也就是执行文件,一般在当前目录下。
     2.gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后,core dump后产生的文件。
     3.gdb <program> <PID> 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。 gdb启动时,可以加上一些gdb的启动开关,详细的开关可以用gdb -help查看。
    
  • gdb调试:

    $ gdb testgdb <---------- 启动gdb 
    (gdb) break 16 <-------------------- 设置断点,在源程序第16行处。 
    (gdb) break func <-------------------- 设置断点,在函数func()入口处。
    (gdb) info break <-------------------- 查看断点信息。
    (gdb) r <--------------------- 运行程序,run命令简写
    (gdb) n <--------------------- 单条语句执行,next命令简写。
    (gdb) c <--------------------- 继续运行程序,continue命令简写。 Continuing. 
    (gdb) p i<--------------------- 打印变量i的值,print命令简写。
    (gdb) bt <--------------------- 查看函数堆栈。 
    (gdb) finish <--------------------- 退出函数。 
    (gdb) c <--------------------- 继续运行。
    (gdb) q <--------------------- 退出gdb。
    

Makefile 使用

  • make工具最主要也是最基本的功能就是根据makefile文件中描述的源程序至今的相互关系来完成自动编译、维护多个源文件工程。而makefile文件需要按某种语法进行编写,文件中需要说明如何编译各个源文件并链接生成可执行文件,要求定义源文件之间的依赖关系

  • 一个Makefile文件主要含有一系列的规则,每条规则包含一下内容:

    一个目标,即make最终需要创建的文件,如可执行文件和目标文件;
    目标也可以是要执行的动作,如‘clean’;
    一个或多个依赖文件的列表,通常是编译目标文件所需要的其他文件。
    
  • 之后的一系列命令,是make执行的动作,通常是把指定的相关文件编译成目标文件的编译命令,每个命令占一行,并以tab开头(初学者务必注意:是tab,而不是空格),执行以上Makefile后就会自动化编译。

教材学习中的问题和解决过程

问题1:dwde有什么区别

  • 解决:dw删除一个单词(包括空格);de删除一个单词(不包括空格)。如图:

  • 当光标位于单词some的首字母s时

  • dw会将整个单词some包括some后的空格一同删除

  • de只能删除单词some,使得单词a和单词words之间出现两个空格

问题2:输入2w3e时光标都向后移动,而不是如教程中说的“输入2w使光标向前移动两个单词,输入3e使光标向前移动到第三个单词的末尾”

  • 解决:查询资料后发现,we操作的共同的基本功能是使光标右移,所以2w3e输入后光标后移是正确的,此处教程出错。

问题3:静态库的使用: gcc -o main main.c -L. -lxxx-L , -l 的含义

  • 解决:选项“-L dir”的功能与“-I dir”类似,能够在库文件的搜索路径列表中添加 dir 目录,而“-lname” 选项指示编译时链接到库文件 libname.a 或者 libname.so。

练习中的问题和解决过程

  • 输入所有代码并gcc编译运行代码

  • 发现运行结果中少了一个功能

  • 检查错误发现main函数中少打了一行printf的代码

  • 最终得到正确的结果

  • 把上述代码中除了main函数外的代码制作成一个静态库math.a时一开始出现错误,后来发现是因为没有用gcc -c先生成静态库

  • 制作共享库math.so

  • 编写makefile,让代码编译,上述静态库和共享库的使用自动化

ubuntu中托管代码出现的问题和解决过程

  • 参照卢肖明同学写的教程首先查看了是否已经安装git

  • 发现git已经安装完毕后按着教程继续往下做

  • 之后出现了被拒绝登录的情况

  • 仔细检查发现配置时将user.email误打成了user.eamil

  • 于是查看git所有配置项

  • 重新配置并继续往下做

  • 又出现了fetch-first的错误

  • 由于这个错误在windows下托管代码时已经遇到过,所以轻松解决

本周代码托管截图及行数统计

其他(感悟、思考等,可选)

  • 本周首先学习的vi命令行模式功能键,由于功能实在太过强大,虽然练习了一遍教程,但是只能记住一些较为常用的操作键,并且在学习的过程中发现使用功能键时需要特别小心,因为有时字母的大写和小写实现的功能会天差地别,比如命令行模式下x可删除光标所在的字符,而X删除的是光标所在的前一个字符,这样微小的差别有时很难注意到,因此我认为最重要的是掌握回到上一步功能——u
  • 这一周的学习内容不仅有电子版还有教材上的内容,感觉学习的内容比较杂,只能看着学习指导一个知识点一个知识点的学,比较没有系统性。
  • 通过在ubuntu上托管代码,深刻的感受到虽然系统不同,但是还是和windows下托管代码有很多的共通之处,更能理解娄老师上课所说的元知识是为何物,也更能体会到老师让我们用不同的工具学习的良苦用心!

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 100/100 1/2 20/20
第二周 76/176 1/3 30/50

参考资料

Copyright © 2024 20145214张宁
Powered by .NET 8.0 on Kubernetes