【计算机系统】计算机系统大作业——程序人生

2164012698.png)

摘 要

        本论文通过hello.c程序,对在CSAPP课程中所学知识进行整理,在Ubuntu虚拟机Linux系统下进行所有操作,运用Linux系统的工具,分析hello程序的一生。

关键词: hello,计算机系统,linux,程序人生

第1章 概述

1.1 Hello简介

Hello的P2P过程:

        在VSCode等编辑器中键入Hello代码得到hello.c程序;对程序进行预处理、编译、汇编、链接生成可执行目标程序;在shell中启动后,shell调用fork创建子进程;hello从Program转换为Process。

Hello的020过程:

        然后shell为hello的execve映射虚拟内存,进入程序入口后开始载入物理内存;进入main函数执行目标代码,CPU为hello分配时间片以执行逻辑控制流;程序运行结束后,shell父进程回收hello进程,释放占用的内存,删除数据结构。

1.2 环境与工具

硬件环境

        X64 CPU;1.6GHz;8G RAM;256G SSD Disk;1T HDD Disk

软件环境

        Windows10 64位;Vmware 14pro;Ubuntu 20.04.2 LTS 64位

开发工具

        Visual Studio Code 64位;vim/gpedit+gcc/as/ld/edb/readelf;

1.3 中间结果

文件的作用 文件名
预处理后的文件 hello.i
编译之后的汇编文件 hello.s
汇编之后的可重定位目标文件 hello.o
链接之后的可执行目标文件 hello
hello.o 的 ELF格式 elf.txt
hello.o 的反汇编代码 hello_o_disass.s
hello的ELF 格式 elf_hello.txt
hello 的反汇编代码 hello_disass.s

1.4 本章小结

        本章简要介绍了hello的P2P,020过程,并列出了大作业的软硬件环境及开发工具,还列出了操作过程中产生的中间结果。

第2章 预处理

2.1 预处理的概念与作用

        预处理又称预编译,(对于c/c++来说)预处理指的是在程序编译之前,根据以字符#开头的命令(即头文件/define等),修改原始的c程序。

预处理的主要作用如下:

●将源文件中以"include"格式包含的文件复制到编译的源文件中。

●用实际值替换用"#define"定义的字符串。

●根据"#if"后面的条件决定需要编译的代码。

2.2在Ubuntu下预处理的命令

命令:gcc -E hello.c -o hello.i
在这里插入图片描述

图 2.1 预处理命令

2.3 Hello的预处理结果解析

        程序扩展为3065行,hello源程序出现在3047行,#include <stdio.h> #include <stdlib.h> #include <unistd.h>三个头文件消失,替代的是一大段代码,描述的是运行库在计算机中的位置,方便下一步翻译成汇编语言。

图 2.2 hello.i库文件

在这里插入图片描述

图 2.3 源代码

2.4 本章小结

        本章主要介绍了预处理的概念和应用功能,同时将hello.c文件进行预处理生成hello.i文本文件,并对生成的hello.i文件进行分析,详细了解了预处理的内涵。

第3章 编译

3.1 编译的概念与作用

        编译是利用编译程序从源语言编写的源程序产生目标程序的过程,是用编译程序产生目标程序的动作,把高级语言变成计算机可以识别的2进制语言。

作用:

        把用高级程序设计语言书写的源程序,翻译成等价的计算机汇编或机器语言书写的目标程序,编译程序以高级程序设计语言书写的源程序作为输入,而以汇编或机器语言表示的目标程序作为输出。

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

3.2 在Ubuntu下编译的命令

命令:gcc -S hello.i -o hello.s
在这里插入图片描述

图 3.1 编译命令

3.3 Hello的编译结果解析

3.3.1 数据

  1. 常量

        字符串:如下两个函数中的字符串被存储在 .rodata节中在这里插入图片描述

图 3.2 printf函数
        存储如下:

在这里插入图片描述

图 3.3 字符串常量存储
  1. 变量

        1) 全局变量

        初始化的全局变量储存在.data节,sleepsecs全局变量被存放在.data节
在这里插入图片描述

图 3.4 sleepsecs存储位置

         2) 局部变量

        局部变量存储在寄存器或栈中。程序中有局部变量 int i

        在汇编代码中如下:
在这里插入图片描述

图 3.5 局部变量i存储位置

         i被存储在栈中,-4(%rbp)的位置。

3.3.2 操作

  1. 算术操作

      在循环操作中,使用 i++ 自增操作,每次循环结束后对 i 加1,对栈上存储i 的位置加1;
在这里插入图片描述

图 3.6 i的自增操作
  1. 关系操作

      1) 程序第16行中判断argc是否等于3,源代码为:
在这里插入图片描述

图 3.7 源代码

      汇编代码为:
在这里插入图片描述

图 3.8 汇编代码

       2) 程序第21行中判断 i 是否小于10,源代码为:
在这里插入图片描述

图 3.9 源代码

      汇编代码为,汇编优化为 i <= 9:
在这里插入图片描述

图 3.10 汇编代码
  1. 控制转移

      在使用比较关系操作进行判断后,程序将按判断结果经如下代码跳转至L2或L4,进入if语句或继续进入循环
在这里插入图片描述

图 3.11 if语句跳转

在这里插入图片描述

图 3.12 for语句跳转
  1. 数组/指针/结构操作

      主函数main的参数中有指针数组char *argv[],argv[0]指向输入程序的路径和名称,argv[1]和argv[2]分别表示两个字符串。
在这里插入图片描述

图 3.13 main函数参数存储

在这里插入图片描述

图 3.14 argv数组实现汇编代码
  1. 函数操作

      1) main函数

      参数传递:传入参数argc,argv[],分别用寄存器%edi和%rsi存储

      函数调用:被系统启动函数调用

      函数返回:设置%eax为0,并返回

在这里插入图片描述

图 3.15 main函数返回

       2) printf函数

       i. call puts@PLT

      参数传递:传入字符串参数首地址

      函数调用:if判断满足条件后被调用

在这里插入图片描述

图 3.16 call puts汇编代码

       ii. call printf@PLT

       参数传递:传入 argv[1]和argc[2]的地址

      函数调用:for循环中被调用

在这里插入图片描述

图 3.17 call printf汇编代码

      3) exit函数

      参数传递:传入参数1

<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值