标准写法

  • 编译hello.c
hello:hello.c
gcc hello.c -o hello # 注意开头的tab, 而不是空格

.PHONY: clean
# 用于指示"clean是一个伪目标", 伪目标相应的命令序列总是会被执行.

clean:
rm hello # 注意开头的tab, 而不是空格

生成目标文件名:依赖文件列表
用于生成目标文件的命令序列 # 注意开头的tab, 而不是空格
  • 更有效率的写法
CC=gcc
CFLAGS=-I.

hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
  • 全部编译
SOURCE = $(wildcard *.c)  
TARGETS = $(patsubst %.c, %, $(SOURCE))

CC = gcc
CFLAGS = -Wall -g

all: $(TARGETS)

%: %.c
$(CC) $< $(CFLAGS) -o $@

.PHONY:clean all

clean:
rm -f $(TARGETS)

Makefile文件的格式

[廖雪峰](http://ruanyifeng.com/blog/2015/02/make.html)

Makefile文件由一系列规则(rules)构成。每条规则的形式如下。

<target>: <prerequisites> 
[tab] <commands>

上面第一行冒号前面的部分,叫做"目标"(target),冒号后面的部分叫做"前置条件"(prerequisites);第二行必须由一个tab键起首,后面跟着"命令"(commands)。

  • 键入make -nB, 它会让make程序以"只输出命令但不执行"的方式强制构建目标。

文件名匹配

%.o: %.c # 所有.o/.c结尾的文件

变量

txt = Hello World
test:
@echo $(txt) # 变量放在$()中,@表示不打印直接执行

第一阶段 程序的表示、转换与链接

参考MOOC:NJU-1001625001

1.0 计算机系统概述

1.3 程序开发和执行过程

  1. hello.c程序用ascii文本表示
  2. 首先.c文件预处理为.i文件(把预处理指令翻译过来),然后.i文件编译成.s文件(汇编程序文本),接着.s文件汇编成.o文件(二进制),与printf等函数的.o文件共同连接成可执行文件(二进制)
  3. 高级语言编写程序所需环境:(1)语言处理程序; (2)语言处理系统; (3)语言运行时的系统; (4)操作系统内核; (5)操作系统; (6)指令集体系结构; (7)人机接口

1.4 计算机系统层次结构

  • 过程式语言:如何做; 非过程化语言:做什么;语言发展是不断抽象的过程
  • 应用->算法->语言->操作系统->(软件)ISA指令集(硬件)->微体系、功能部件、电路和器件
    非预期结果是硬件层次造成的。上层是下层的抽象,下层是上层的实现,底层为上层提供支撑环境
  • 题目:由机器语言编程的早期计算机系统中,没有ISA这一层次(F);一直都有ISA,因此ISA是计算机体系层次中最重要的层次
    ISA, Instruction Set Architecture(结构)规定了如何使用硬件,是可以执行的指令的集合,包括指令格式、操作种类及操作数的类型的规定…
    没有ISA,软件无法使用计算机硬件,一台计算机就不能成为“通用”计算机
  • 计算机组成必须能够实现ISA规定的功能;同一种ISA可以由不同的计算机(硬件)组成,如乘法指令用ALU或乘法器都可以实现
  • 题目:有没有乘法指令是ISA考虑的问题,如何实现乘法指令是微体系结构考虑的问题

1.5 计算机系统基础学习目标

  • 编写高效程序必须了解计算机底层结构
  • 必须掌握并行程序设计技术和工具
  • 课程目标:理解计算机如何生成和运行可执行文件
  • 涉及层次:C语言设计层,ISA和汇编层,微体系结构和硬件层
  • 第一部分 程序表示与转换;第二部分 执行控制流
阅读全文 »

  • 复杂度分析:数据结构和算法的评价维度与方法。时间复杂度、空间复杂度的推算方法、常见类型、示例等。
  • 数据结构:基本数据类型,数据结构的分类方法。数组、链表、栈、队列、哈希表、树、堆、图等数据结构的定义、优缺点、常用操作、常见类型、典型应用、实现方法等。
  • 算法:搜索、排序、分治、回溯、动态规划、贪心等算法的定义、优缺点、效率、应用场景、解题步骤、示例题目等。
阅读全文 »

1.0 CSAPP 阅读指南

参考:https://book.douban.com/review/3150951/
  • 这本书的简介(引言)部分简介明了:一个简单的hello world程序在计算机上的执行过程,预处理->编译->汇编->链接->生成可执行目标文件->载入内存->数据流->屏幕输出显示,没有一句废话,简介扼要,总结成一句:计算机系统=位+上下文。

  • 关于二进制的内容个人感觉有些冗余,这部分内容偶基本是一扫而过,毕竟从小到大这些内容学了都快有十多遍了,而平时编程真能用到的二进制技巧基本也就移位和bit flag这两招。不过这章里有不少small tricks值得一耍(最经典的就是不用临时变量交换两个数)。话说回来,真要想在二进制上玩出花来,参考Hacker’s delight会有更大的惊喜。

  • 程序的机器级表示这一章偶花了不少时间阅读,毕竟偶没学过汇编,基础基本为0。不过这本书里出现的汇编指令绝大多数都由运算、取数存数、跳转这三种指令所组成,所以在阅读上不会存在任何难度。   这部分融合了程序员所需了解的编译和汇编这两样课程中的基础知识:想知道for、do…while、while三种循环的实质性区别?想知道多重if和 switch的本质区别?想知道数组的存储方式?想知道数组下标读取和指针读取的区别?想知道递归过程调用的背后实现机理?看看这一章,相信你会对C语言乃至程序设计语言有更深的理解。

  • 指令集&体系结构这一章,两位作者为了让读者更好的理解指令集(X86),别具一格的搞出了一个简化版的Y86指令集,并用其表示基本的运算和控制,甚至连数字电路的HCL都来了一笔(暴汗)。数据流、组合逻辑和流水线,图示+详细的讲解,一目了然。国内的计组教科书应该多借鉴一下。

  • 程序性能优化这一章对程序员尤其实用,毕竟,正如TDD和XP的开创者Kent Beck所说,make it run, make it right, make it fast。而第三步又是最麻烦的一步,确认和消除性能的瓶颈,有时比Debug还要恐怖,所以Knuth大神说:Premature optimization is the source of evil。    CSAPP通过展示一个简单的连续数求和和求积运算的小程序,通过性能监测,一步步的优化性能:减少过程调用、消除无关存储器引用、将下标引用切换到指针这些还是比较好理解的,然而后面的根据指令集展开循环、通过指令集来编写更具并行性的代码以及转移预测代价这些机器相关的优化的东东就开始颠覆我的世界观了,原来程序还可以这么搞,I服了U。    唯一的遗憾就是这章的篇幅有些短小,对程序员最为重要的机器无关的程序优化介绍的也并不充分,与此相比,偶感觉programming pearls和practice of programming里面对性能优化的介绍更胜一筹。

  • 存储器体系结构的内容用五个字概括就是:利用局部性。   只有了解了计算机的梯形存储器体系结构,才能体会到为什么同样逻辑的程序会产生如此之大的性能差距,虽然计算机设计者的初衷是把存储器当成一个巨型数组。然而这个大号数组的不同体位的差距还是非常大地,搞不好就郁闷鸟。尤其是DRAM-Disk这一段,足足10的六次方的差距,所以CSAPP专门开了VM 一章来详细讲述。

  • 链接这部分内容篇幅不多,原理上讲的很简洁,文件节和符号解析表只是给出了几个图示,并没有过多的关注其实现。CSAPP把重点放在了链接对源代码产生的影响,同时也让偶再次理解到了全局变量很邪恶。动态链接部分让偶恍然大悟,.net里面的反射和程序集,放到C里面就是动态调用和共享库,都是相通的,无非C的代码更诡异一些。

  • 异常控制流这一章的名字比较囧,以至于我刚开始认为它会介绍点诸如try…catch的异常处理机制。然而看了才明白,它介绍的是更为广义的exception,既包括硬件中断,也包括故障中断,比如说陷入(trap)和故障(fault)。   这一章做的比较绝的是,通过讲述异常流,引入了OS中最核心的概念:进程。然而它并不在进程的具体特性上下文章,而是通过讲述unix下进程相关的api 及使用,从一种程序员的角度告诉你,进程是这么用的,进程之间是这么交换信息的。到最后捎带介绍了一下C里面的非局部跳转(更加强大的Goto,也就是 setjmp和longjmp),别以为只有C++和Java才有异常处理机制,C一样可以做到。

  • 程序的时间度量这一章感觉用处不大,遂跳过

  • 虚拟内存这一章从原理和实现两个不同的层面介绍了存储器体系结构的核心部分:VM。说实话,之前学习VM顶多就是冲着局部性去的,但没想到VM可以做的事有这么多,无论是存储器磁盘映射,还是malloc在磁盘上分配空间返回地址至PTE,都让偶对VM有了一个崭新的认识,原来VM还可以这么用。为了帮助读者深入理解内存的分配机制,作者甚至搞出了一个malloc的实现,从源代码来讲解内存分配、碎片合并、垃圾回收这些概念,帅气。

  • 系统级IO,网络编程以及并发编程这些东东打算之后再慢慢研究,遂跳过

2.0 CSAPP重点解读

3.0 数据选择器&分配器

1 数据分配器

  • 根据输入(地址信号)将一路数据分配到指定输出通道
  • 一路输入,多路输出
    ![[…/Source/Photo/数字逻辑/数据分配器.png]]

2 数据选择器

  • 从多路输入选择一条输出
  • 又称为多路选择器,多路开关
  • 多路输入,一路输出
    ![[…/Source/Photo/数字逻辑/数据选择——定义.png]]

3 LS151制图步骤

  • 情况1:三个输入端正好对应三个变量
  • 根据Y = A2、A1、A0列出最小项,按顺序写出Y=1时有D几
  • 存在的项D取1
    ![[…/Source/Photo/数字逻辑/151制图步骤.png]]
  • 情况2:三个输入端对应四个变量
  • 列出最小项,尽可能合并成只有三项的形式
  • 将第四项作为变量接入
    ![[…/Source/Photo/数字逻辑/151制图-3输入4变量情况1.png]]
    ![[…/Source/Photo/数字逻辑/151制图-3输入4变量情况2.png]]
阅读全文 »

objdump反汇编文件

  • 需要配合gcc -g使用
objdump -S file.o > fileo.txt  // -S 表示显示源代码
objdump -S file > file.txt

// gcc编译步骤
-E // .c -> .i
-S // .i -> .s
-c // .s -> .o
  • .o文件的地址一般从0开始,可执行文件的地址是操作系统给定的虚拟地址

  • 数组:
    1. 不灵活
  • 动态数组:
    1. 使用malloc,在程序运行时(而不是一开始)分配内存
    2. 内存不一定连续,每次调用malloc都需要新的指针
  • 链表:
    1. 解决malloc需要太多指针的问题,每个链表指向下一个指针
    2. 没有链表指向第一项的地址,因此需要头指针
0%