哈工大-计算机系统-2022 | 大作业

计算机系统

大作业

题目 程序人生-Hello’s P2P
专业 计算学部
学号 120L021403
班级 2003011
学生 冯新航
指导教师 郑贵滨

计算机科学与技术学院

2022年5月

摘 要

计算机系统是人类创造出的工业奇迹之一,其构造之精妙,功能之强大,令人赞叹。要全面描述计算机系统的方方面面实际上是非常困难的,因此本文从简单的 hello 程序入手,讲述计算机系统的一些基本概念、功能与原理。我们将讲述 hello 是如何从源码编译为可执行文件,并经由 shell 执行的过程,剖析一些概念的细节和实现原理。

关键词:Linux C语言 计算机系统 编译 内存管理 进程

文章目录

第 1 章 概述

1.1 Hello简介

根据Hello的自白,利用计算机系统的术语,简述Hello的P2P,020的整个过程。

hello 程序在 Linux 下将经历以下步骤:

  • 由文本编辑器编写成 hello.c 源文件
  • 由编译预处理器将其预处理成 hello.i 文件
  • 由汇编器将其翻译成汇编语言文件 hello.s
  • 由编译器将其编译成可重定向目标文件 hello.o
  • 由链接器 ldhello.o 与系统的其他目标文件链接起来,形成最终的 hello 可执行文件
  • shell 中输入相应命令后,shell 为其 fork 一个子进程,经由 execve 函数,使得子进程代表用户执行 hello 程序
  • 此过程中,该函数将 hello 可执行文件映射到虚拟内存,而后载入物理内存,进入 main 函数执行
  • 调度器调度该进程执行控制流,直到 main 函数返回
  • shell 回收该进程,内核删除相关数据结构

1.2 环境与工具

列出你为编写本论文,折腾Hello的整个过程中,使用的软硬件环境,以及开发与调试工具。

硬件环境

  • CPU: Intel Core i7-10875H @ 16x 2.304GHz
  • GPU: NVIDIA GeForce RTX 2060
  • RAM: 40GB DDR4 3200

软件环境

  • 操作系统:Windows 11 Home China、Ubuntu 20.04 (on the Windows Subsystem for Linux)

开发工具

  • Visual Studio Code

1.3 中间结果

列出你为编写本论文,生成的中间结果文件的名字,文件的作用等。

  • hello.c 源代码文本
  • hello.i 编译预处理文件
  • hello.s 汇编文本文件
  • hello.o 可重定位目标文件
  • hello 可执行文件

1.4 本章小结

本章讲述了 hello 程序如何从源代码文本转换为可执行文件的过程,同时列出了实验环境等相关信息。

第 2 章 预处理

2.1 预处理的概念与作用

  • 概念:

    编译预处理器是针对源代码中的编译预处理指令进行的一类操作,如引入头文件、条件编译等

  • 作用:

    处理 #include 指令,将 #include 后的文件原封不动地拷贝到源码对应位置

    处理条件编译指令 #ifdef 等,保留满足条件的源码代码

    替换由 #define 定义的常量等

2.2 在Ubuntu下预处理的命令

应截图,展示预处理过程!

命令:

gcc -E hello.c -o hello.i

截图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIpRjdSD-1653009846945)(https://s1.ax1x.com/2022/05/20/OqqpZt.png)]

2.3 Hello的预处理结果解析

编译预处理器按照C语言标准规则修改和替换源码中某些位置的代码,我们可以在得到的 hello.i 底部找到原来的部分,而在顶端是由 #include 引入的头文件,它被原封不动地拷贝到对应位置。

2.4 本章小结

本章讲述了编译预处理器和编译预处理指令的相关概念及其作用,本质上是修改源文件的文本内容,为编译器将其编译成汇编语言做准备。

第 3 章 编译

3.1 编译的概念与作用

编译器将编译预处理文件 hello.i 编译成汇编文件 hello.s ,这个文件仍然是一个文本文件,内容是 hello 源文件的等价汇编结果。

注意:这儿的编译是指从 .i 到 .s 即预处理后的文件到生成汇编语言程序

3.2 在Ubuntu下编译的命令

编译命令:

gcc -S -g hello.c -o hello.s

应截图,展示编译过程!

3.3 Hello的编译结果解析

此部分是重点,说明编译器是怎么处理C语言的各个数据类型以及各类操作的。应分3.3.1~ 3.3.x等按照类型和操作进行分析,只要 hello.s 中出现的属于大作业PPT中P4给出的参考C数据与操作,都应解析。

3.3.1 汇编文件头
	.file	"hello.c"
	.text
.Ltext0:
	.section	.rodata
	.align 8
.LC0:
	.string	"\347\224\250\346\263\225: Hello \345\255\246\345\217\267 \345\247\223\345\220\215 \347\247\222\346\225\260\357\274\201"
.LC1:
	.string	"Hello %s %s\n"
	.text
	.globl	main
	.type	main, @function

各部分内容说明:

  • .file 声明源文件
  • .text 代码段
  • .section.rodata 数据段
  • .align 地址对齐方式
  • .string 声明字符串
  • globl 声明全局符号
  • .type 声明符号类型
3.3.2 数据
  • 字符串

    main 函数中存在对 printf 的调用,格式控制字符串的地址作为 printf 的参数被传入,如对于:

    printf("用法: Hello 学号 姓名 秒数!\n");
    

    的汇编为:

    leaq	.LC0(%rip), %rdi
    call	puts@PLT
    
  • 局部变量

    main 函数中有局部变量 i 作为循环变量,由语句:

    cmpl	$7, -4(%rbp)
    

    可知该变量存储在栈上,位置为 %rpb-4

  • argcargv 参数

    argcargv 都是 main 的参数,在 main 函数开头有

    movl	%edi, -20(%rbp)
    movq	%rsi, -32(%rbp)
    

    可知这些变量都存储在栈上。

  • 立即数

    立即数是直接硬编码在汇编代码中的。

3.3.2 函数
  • 函数调用、参数传递与返回

    sleep(atoi(argv[3])) 调用为例,调用 sleep 函数需传入调用 atoi 的返回值,在调用 atoi 时,先访问 argv[3] 将其值保存到 %rdi

    movq	%rax, %rdi
    call	atoi@PLT
    

    atoi 中以 ret 返回,返回值保存在 %rax 中,再将返回值作为 sleep 函数参数传入:

    movl	%eax, %edi
    call	sleep@PLT
    
3.3.3 赋值

赋值语句对应 x86 汇编中的 mov 指令,后缀表示操作的字节数,如:

movq	(%rax), %rax

%rax 作为内存地址,取地址的值(四字)传入 %rax

其他后缀,有:

  • movb 单字
  • movw 双字
  • movl 四字
  • movq 八字
3.3.4 算术操作

四则运算在 x86 有指令直接实现,如:

addl	$1, -4(%rbp)

%rbp-4 的内存引用值加一,即 i++

其他指令的使用方法如图所示:

3.3.5 关系与条件转移

hello.c 的第一个判断语句为例:

if (argc != 4)
{
   
    printf("用法: Hello 学号 姓名 秒数!\n");
    exit(1);
}

汇编如下:

cmpl	$4, -20(%rbp)
je	.L2
.loc 1 16 3
leaq	.LC0(%rip), %rdi
call	puts@PLT
.loc 1 17 3
movl	$1, %edi
call	exit@PLT

因为 %rbp-20 就是 argc 的地址,将其与 4 比较,cmpl 会修改条件码寄存器,je 指令根据条件码寄存器的值决定是否转跳,此处可知,只有相等时转跳,不相等时进入 if 代码块内。

i < 8 ,同理:

cmpl	$7, -4(%rbp)
jle	.L4
3.3.6 类型转换

机器级的类型转换,如基本类型 int float double short 等是通过二进制表示的截断与扩展实现的。

字符串与数字间的类型转换则利用 atoi 这样的函数实现。

3.4 本章小结

本章对 hello.chello.i ,即源码到汇编的对应关系做出解释,讲述了 x86 的基本汇编命令的作用。

第 4 章 汇编

4.1 汇编的概念与作用

注意:这儿的汇编是指从 .s 到 .o 即编译后的文件到生成机器语言二进制程序的过程。

汇编器将汇编语言文本翻译成机器语言,产生二进制文件,并将这些文件打包成可重定向目标文件,将各类信息存储在文件头中。

4.2 在Ubuntu下汇编的命令

命令:

gcc -c -g hello.s -o hello.o

4.3 可重定位目标 elf 格式

分析 hello.o 的ELF格式,用 readelf 等列出其各节的基本信息,特别是重定位项目分析。

编译命令:

  • gcc -c hello.s -o hello.o

ELF

命令:

readelf -h hello.o

结果:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          1240 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         14
  Section header string table index: 13

ELF 头描述了该可重定向目标文件的一些信息,可以帮助链接器链接文件,其中包括了 ELF 头的大小、目标文件类型、各节的大小和偏移等信息。

在本例中,可以看见这个可重定向目标文件有 14 个节。

节分布

命令:

readelf -S hello.o

结果:

There are 14 section headers, starting at offset 0x4d8:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000092  0000000000000000  AX       0     0     1
  [ 2] .rela.text        RELA             0000000000000000  00000388
       00000000000000c0  0000000000000018   I      11     1     8
  [ 3] .data             PROGBITS         0000000000000000  000000d2
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .bss              NOBITS           0000000000000000  000000d2
       0000000000000000  0000000000000000  WA       0     0     1
  [ 5] .rodata           PROGBITS         0000000000000000  000000d8
       0000000000000033  0000000000000000   A       0     0     8
  [ 6] .comment          PROGBITS         0000000000000000  0000010b
       000000000000002a  0000000000000001  MS       0     0     1
  [ 7] .note.GNU-stack   PROGBITS         0000000000000000  00000135
       0000000000000000  0000000000000000           0     0     1
  [ 8] .note.gnu.propert NOTE             0000000000000000  00000138
       0000000000000020  0000000000000000   A       0     0     8
  [ 9] .eh_frame         PROGBITS         0000000000000000  00000158
       0000000000000038  0000000000000000   A       0     0     8
  [10] .rela.eh_frame    RELA             0000000000000000  00000448
       0000000000000018  0000000000000018   I      11     9     8
  [11] .symtab           SYMTAB           0000000000000000  00000190
       00000000000001b0  0000000000000018          12    10     8
  [12] .strtab           STRTAB           0000000000000000  00000340
       0000000000000048  0000000000000000           0     0     1
  [13] .shstrtab         STRTAB           0000000000000000  00000460
       0000000000000074  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

此处可以看到各节的类型、大小、位置等信息,还可以看出各节的可执行或可读情况。

符号表

命令:

readelf -s hello.o

结果

Symbol table '.symtab' contains 18 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
     9: 000
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值