【Linux C与C++一线开发实践】之一 Linux概述与Linux C++开发

2023-05-16

Linux系统启动的基本过程

对于一台Linux系统来说,用户按下开机按钮后,一共要经历如下几个过程。

上电
BIOS自检
系统引导
启动内核

下面我们来详细分析这几个过程:

  1. 按下电源
    上电后,CPU的RESET引脚会由特殊的硬件电路产生一个逻辑值,这就是常说的CPU复位,此时CPU被唤醒了,CPU将在0xfffffff0处执行一条长跳转指令,直接跳转到固化的ROM中的启动代码处(这里代码软件就是BIOS),并开始执行BIOS程序。

  2. BIOS自检
    早期BIOS芯片确实只是“只读内存”(Read-Only Memory, ROM),里面的内容是用一种烧录器写入的,一旦写入就不能更改,除非更换芯片。现代的主板都是用一种叫Flash EPROM的芯片来存储系统BIOS,里面的内容可使用主板厂商提供的擦写程序擦除后重新写入,这样就给用户升级BIOS提供了极大的方便。
    2.1硬件自检
    BIOS程序的主要作用就是硬件自检,主要负责检测系统外围关键设备(如CPU、内存、显卡、I/O、键盘鼠标等)是否正常。比如,我们常见的内存松动的情况,BIOS自检阶段就会报错。自检中报错将按两种情况处理:一,对于严重故障,直接停机,此时由于各种初始化操作还没完成,因此不能给出任何提示。二,对于非严重故障则给出提示或声音报警,等待用户处理。如果没有问题,屏幕上就会打印显示出CPU、内存、硬盘等信息。
    2.2查找引导设备
    硬件自检完成后,然后按照一定的顺序启动这些硬件设备(常设置的启动顺序就是指这个),并找到下一阶段的启动程序(系统引导)将控制权交给它。

  3. 系统引导(查找系统位置)
    BIOS找到引导程序把控制权交给它并把它载入内存后就退出了。在接着讲系统引导之前我们先来了解下这个引导程序到底在哪里加载的呢?
    我们存储设备前512个字节被定义为“主引导记录”。可以根据这段记录确定我们要引导的操作系统位于硬盘的那个位置,然后启动它。

主引导分区示意图:

1~446字节 机器码447~510字节 分区表511、512字节 记录标志

其中分区表的作用是将硬盘分成若干个区。它的长度只有64个字节,里面又分成4项,每项16个字节。所以,一个硬盘最多只能分4个一级分区,又叫“主分区”。每个主分区的16字节由下面6部分组成。

1字节 是否为激活分区2~4字节 第一个扇区物理位置5字节 主分区类型6~8字节 最后一个扇区物理位置9~12字节 第一个扇区逻辑地址13~16字节 扇区总数

最后4个字节决定了这个主分区的长度。最多不超过2的32次方,如果每个扇区为512字节,就意味着单个分区最大不超过2TB。再考虑到扇区的逻辑地址也是32位,所以单个硬盘可利用的空间最大也不超过2TB。如果想使用更大的硬盘就只有两个办法:一是提高每个扇区的字节数,二是增加扇区总数。
随着硬盘越来越大,4个主分区已经不够了,然后引进了扩展分区的概念。规定4个主分区中有且只有一个可以定义为扩展分区,这个扩展分区可以包含一个或多个逻辑分区。

最后说说主引导分区中最后两个字节,如果最后两个字节是0x55和0xAA,就表明可以启动,操作系统在这个硬盘上。至此系统引导结束,控制权交给操作系统。

  1. 启动内核
    控制权交给操作系统后,操作系统的内核首先被载入内存。先载入/boot目录下面的内核文件,内核加载成功后,第一个运行的程序是/sbin/init。它根据配置文件(/etc/initab)产生init进程。这是Linux启动的第一个进程,PID=1。然后init进程加载系统的各个模块,比如窗口程序和网络程序,直至执行/bin/login程序,跳出登入界面,等待用户输入用户名和密码。至此,全部启动过程完成。

环境变量

环境变量通常是指在操作系统中用来指定操作系统运行环境的一些变量,比如PATH变量包含一系列由冒号分隔开的目录,系统就是从这些目录里寻找可执行文件的。
环境变量分为:系统环境变量和用户环境变量。
(1)系统环境变量存放在/etc/profile文件中。该文件作用于登入到系统的每一个用户。修改该文件中的环境变量将作用于系统的每个用户。
(2)用户环境变量存放在各个用户的~/.bash_profile文件中,~表示每个用户的宿主目录(home目录)。.bash_profile是一个隐藏文件,我们在进入~后,通过ls -a可以看到该文件。修改该文件中的变量将仅影响该文件对应的用户。
可以用env命令来显示当前用户的环境变量。

Linux下gcc/g++编译器使用

编译过程分析

gcc是可以在多种硬件平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比,平均效率要高20%~30%。很多人都知道它可以编译C语言源程序,其实还可以用来编译C++语言源程序。虽然另一个C++编译工具g++更专业些,但作为一个C++开发者,学会gcc工具的使用也是必备技能。
首先我们来分析下一个C语言源程序到可执行程序的过程。如下:

汇编--二进制
预处理
编译
链接
可执行程序

我们还是以Hello world示例代码来分析这几个过程。

//文件名:test.c
#include <stdio.h>

int main(int argc, char *argv[])
{
        char sz[] = "Hello world!\n";
        printf("%s", sz);
        fflush(stdout);
        return 0;
}
  1. 预处理
    预处理就是对源程序中的伪指令(以#开头的指令)和特殊符号进行处理的过程。伪指令包括宏定义指令、条件编译指令和头文件包含指令。gcc对C源文件进行预处理后会输出.i文件。
    预处理过程主要是处理源代码中以#开始的预编译指令,处理规则如下:
    (1)将所有的#define宏定义替换
    (2)处理所有条件编译指令,如#if、#ifdef等。
    (3)将#include文件插入,该过程是递归进行的,被包含的文件可能还包含其他文件。
    (4)删除所有的注释
    (5)添加行号和文件标识,以便于编译时编译器产生调试用的行号信息及编译时产生编译错误或警告时能够显示行号信息。
    (6)保留所有的#pragma编译器指令,因为编译器需要使用它们。

下面是我们通过gcc编译的一个预处理示例:

gcc -E test.c -o test.i   //-E告诉gcc只进行预处理  -o是输出结果文件

通过cat -n test.i查看生成的test.i预处理文件最后部分截图:
在这里插入图片描述

  1. 编译阶段
    编译阶段就是把预处理文件进行一系列的词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。默认情况下,这个文件不会生成,而是直接把它接着处理生成二进制文件。
    如果想看这个中间汇编代码文件可以用-S选项指定生成,汇编代码文件后缀是.s文件。
gcc -S test.i -o test.s  //把预处理文件生成汇编文件

同样用cat命令查看,部分截图如下:
在这里插入图片描述
接着来看看汇编代码怎么到二进制文件的。
每一个汇编语句几乎都对应一条机器指令。所以这个过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。
gcc生成的二进制代码文件后缀名为.o的文件。我们把上面的test.s文件编译为test.o文件,通过指令-c生成:

gcc -c test.s -o test.o  //汇编代码到二进制代码(windows上对应的是obj文件)

二进制文件(不是文本文件) ,不能用cat查看,可以通过命令hexdump查看。
在这里插入图片描述

  1. 链接阶段
    链接主要是为了解决多个文件之间相互引用的问题。上面编译阶段只对单个文件进行处理,如果这个文件里面需要引用到其他文件中的符号(全局变量或者函数库中的某个函数),那么这时在这个文件中该符号的地址是没法确定的,只能等链接器把所有的目标文件连接到一起后才能确定最终的地址,最终生成可执行的文件。
    在链接阶段,所有的目标文件被安排在可执行程序中的恰当位置。要注意一点是,在Linux中,可执行文件没有统一的后缀,系统是根据文件属性来区分是否是可执行文件的。
    下面我们对test.o进行链接:
//链接生成可执行文件test
gcc test.o -o test  

//如果有多个目标文件,可以写一起中间加空格隔开
gcc test1.o test2.o test3.o -o test

在这里插入图片描述
至此我们对test.c源程序到生成可执行程序整个过程就分析完了。当然实际开发中我们不需要这么麻烦,只需要gcc test.c -o test就可以了,它并不会生成那些中间文件。

gcc常用命令参数

gcc选项有上百个,当然很多都用不到,我们只需熟悉一些常见的即可。还有注意gcc选项区分大小写,比如-o与-O,前者是生成一个结果文件,后者表示对生成的可执行文件进行一级优化。

  1. 没有任何选项
    gcc test.c,它会默认生成可执行文件a.out。

  2. 选项-x
    告诉gcc编译的源文件是什么语言,而不用根据其后缀去判断。这主要用于我们不想暴露源文件类型的场景,如我们把c源程序命名为test.pig,我们可以这样编译:
    gcc -x c test.pig

  3. 选项-o
    用于指定要生成的结果文件,结果文件可以是预处理文件、汇编文件、目标文件、或者最终的可执行文件。

  4. 选项-c
    对源文件进行编译,但不进行链接。此时,将生成目标文件,如果没有指定输出文件名,就会默认生成同名的.o文件。
    比如:gcc -c test.cpp
    生成:test.o

  5. 选项-I
    指定头文件所在路径,就是include头文件的查找路径。说到这里,顺便说下include <test.h>与include "test.h"的区别,就是查找头文件路径有点区别。
    <>尖括号形式,首先去-I指定的路径找,然后到标准默认路径/usr/local/include下找,最后到/usr/include找,都找不多则报错。
    “”双引号形式,只是首先它会在当前工作目录找(源程序所在目录),然后后面和<>形式一样了。

  6. 选项-include
    在命令中也可以包含头文件。这样我们可以在源码中隐藏头文件的include。格式如下:
    gcc [srcfile] -include [headfile]

  7. 选项-Wall
    显示所有的警告信息。
    例: gcc test.cpp -Wall -o test

  8. 选项-g
    产生供gdb调试用的可执行文件。因此,加了这个选项后,产生的可执行文件尺寸要大些。
    例:gcc test.cpp -g -o test

  9. 选项-pg
    产生供gprof剖析用的可执行文件。gprof是Linux下对C++程序进行性能分析的工具。

  10. 选项-l
    用来链接共享库。例如编译一个使用了C++标准库内容的程序,则需要链接C++标准库,如:
    gcc test.cpp -lstdc++ -o test
    其中,stdc++是C++标准库名字,它和l之间没有空格。

最后g++的使用其实和gcc差不多,对于c++程序g++使用更简单。像上面提到的gcc编译c++可能要-l来链接c++库,而g++就不需要,它会自动链接。

Linux下 gdb调试

首先被gdb调试的可执行程序要是加了-g选项的调试版本才能调试。下面我们我列出几个常用的调试命令:

启动:gdb-->file xx或者gdb xx
退出:quit
list或l:显示代码(可以跟两个参数,指定显示代码范围)
break n:下断点
delete [n]:删除断点
info break:显示断点清单
info local:显示当前函数中的局部变量信息
run:运行启动的程序
c:继续运行
next:下一步不进入函数内部
step:下一步进入函数内部
backtrace:显示堆栈信息
print:打印变量的值

更详细的可以通过help帮助命令查看。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux C与C++一线开发实践】之一 Linux概述与Linux C++开发 的相关文章

  • vmsplice() 和 TCP

    在原来的vmsplice 执行 有人建议 http lwn net Articles 181169 如果您的用户态缓冲区是管道中可容纳的最大页面数的 2 倍 则缓冲区后半部分成功的 vmsplice 将保证内核使用缓冲区的前半部分完成 但事
  • 批量删除文件名中包含 BASH 中特殊字符的子字符串

    我的目录中有一个文件列表 opencv calib3d so2410 so opencv contrib so2410 so opencv core so2410 so opencv features2d so2410 so opencv
  • 找不到包“gdk-pixbuf-2.0”

    我正在尝试在 Amazon Linux 发行版实例上构建 librsvg 我已经通过 yum 安装了大部分依赖项 其中一些在实例上启用的默认 yum 存储库中不可用 因此必须从头开始构建它们 我已经走了很远 但还停留在最后一点 跑步时sud
  • 仅使用containerd(不使用Docker)修剪容器镜像

    如果我刚刚containerd安装在 Linux 系统上 即 Docker 是not安装 如何删除未使用的容器映像以节省磁盘空间 Docker 就是这么方便docker system prune https docs docker com
  • 为什么 Linux 没有 DirectX API?

    在考虑现代显卡的 Windows 系统上 DirectX API 的驱动程序端实现时 我想知道为什么此实现在非 Windows 系统 尤其是 Linux 上不可用 由于明显缺乏此功能 我只能假设有一个我无视的充分理由 但在我的原始理解中 我
  • docker 非 root 绑定安装权限,WITH --userns-remap

    all 尝试让绑定安装权限正常工作 我的目标是在容器中绑定安装卷 以便 a 容器不以 root 用户身份运行入口点 二 docker daemon 配置了 userns remap 这样容器 主机上没有 root c 我可以绑定挂载和读 写
  • 使用 \r 并打印一些文本后如何清除控制台中的一行?

    对于我当前的项目 有一些代码很慢并且我无法使其更快 为了获得一些关于已完成 必须完成多少的反馈 我创建了一个进度片段 您可以在下面看到 当你看到最后一行时 sys stdout write r100 80 n I use 80覆盖最终剩余的
  • Linux 上的 Pervasive ODBC 错误 [01000][unixODBC][驱动程序管理器]无法打开 lib '/usr/local/psql/lib/odbcci.so':找不到文件

    我正在尝试让 Pervasive v10 客户端 ODBC 在 Centos 6 上运行 据我所知 没有 64 位 ODBC 客户端 因此我必须使用 32 位客户端 我终于成功安装了它 但尝试使用时出现以下错误 isql v mydsn 0
  • GMail 421 4.7.0 稍后重试,关闭连接

    我试图找出为什么它无法使用 GMail 从我的服务器发送邮件 为此 我使用 SwiftMailer 但我可以将问题包含在以下独立代码中
  • .net-core:ILDASM / ILASM 的等效项

    net core 是否有相当于 ILDASM ILASM 的功能 具体来说 我正在寻找在 Linux 上运行的东西 因此为什么是 net core ildasm 和 ilasm 工具都是使用此存储库中的 CoreCLR 构建的 https
  • 从 Xlib 转换为 xcb

    我目前正在将我的一个应用程序从 Xlib 移植到 libxcb 但在查找有关我有时使用的 XInput2 扩展的信息时遇到了一些麻烦 libxcb 中有 XInput2 实现吗 如果是的话 在哪里可以找到文档 目前我在使用此功能时遇到问题
  • 与 pthread 的进程间互斥

    我想使用一个互斥体 它将用于同步对两个不同进程共享的内存中驻留的某些变量的访问 我怎样才能做到这一点 执行该操作的代码示例将非常感激 以下示例演示了 Pthread 进程间互斥体的创建 使用和销毁 将示例推广到多个进程作为读者的练习 inc
  • Mac OS X 上的 /proc/self/cmdline / GetCommandLine 等效项是什么?

    如何在不使用 argc argv 的情况下访问 Mac OS X 上的命令行 在 Linux 上 我会简单地阅读 proc self cmdline or use GetCommandLine在 Windows 上 但我找不到 Mac OS
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 在生产服务器上使用 Subversion 使文件生效的最佳方法是什么?

    目前我已经设置了 subversion 这样当我在 Eclipse PDT 中进行更改时 我可以提交更改 它们将保存在 home administrator 中项目文件 该文件具有 subversion 推荐的 branches tags
  • 检查已安装的软件包,如果没有找到则安装

    我需要检查已安装的软件包 如果未安装则安装它们 RHEL CentOS Fedora 示例 rpm qa grep glibc static glibc static 2 12 1 80 el6 3 5 i686 如何在 BASH 中进行检
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • x86-64 AMD 上 CALL 指令的操作数生成

    以下是示例程序 objdump 的输出 080483b4
  • ansible unarchive 模块如何查找 tar 二进制文件?

    我正在尝试执行一个 ansible 剧本 该剧本的任务是利用unarchive模块 因为我是在 OSX 上执行此操作 所以我需要使用它gnu tar 而不是bsd tar通常与 OSX 一起提供 因为BSD tar 不受官方支持 https
  • 无法显示 Laravel 欢迎页面

    我的服务器位于 DigitalOcean 云上 我正在使用 Ubuntu 和 Apache Web 服务器 我的家用计算机运行的是 Windows 7 我使用 putty 作为终端 遵循所有指示https laracasts com ser

随机推荐

  • 【ubuntu】ubuntu14.04、16.04、18.04 LTS版本支持时间

    0 历史版本下载地址 http old releases ubuntu com releases http mirrors 163 com ubuntu releases 1 官网说明 https wiki ubuntu com Kerne
  • 树莓派,tx2硬件对比

    具体参考以下链接 http www exuehao com article detail 14
  • Gazebo中的平面运动 (urdf+控制器设置)及所遇见的问题

    这里有个视频 xff0c 介绍怎么让机器人在平面运动 xff08 在x和y方向上进行平移 xff09 xff1a https www youtube com watch v 61 mtSpqObg9X4 如果你们看不了视频也没关系 xff0
  • 2014年年终总结:写书成长,承载收获

    雪花纷飞 xff0c 任你飘落凝成魅力的雪域之城 美丽的守候 xff0c 望长城内外惟余莽莽 数着北国春夏秋冬的每一天 xff0c 2014 的日历天天换新装 xff0c 消瘦了你的时光 但丰盈了我的渴望 2014 年 xff0c 在你的身
  • 漫步数学分析三十五——乘法法则与梯度

    微分中另一个有名的法则是乘法法则或莱布尼兹法则 定 理 6 令 A R n 是开集 xff0c f A R m g A R 是可微函数 xff0c 那么 g f 是可微的并且对于 x A D g f x R n R m 为 D
  • CAN总线标准及协议分析

    目录 1 简介 2 CAN总线标准 2 1 物理层 2 1 1 CAN总线网络 2 1 2 CAN收发器 2 1 3 CAN信号表示 2 1 4 CAN信号传输 2 2 数据链路层 2 2 1 数据帧 2 2 1 1 帧起始与结束帧 2 2
  • Eclipse中Python开发环境搭建详细图文教程(Windows环境)

    转载请注明出处 Eclipse可便捷的集成开发Python xff0c 这里我们为了更好地使用Python进行机器学习 xff0c 首先进行Eclipse中Python开发环境的搭建 一 下载EclipseIDE 下载地址 xff1a ht
  • FreeRTOS系列|多任务调度

    多任务调度 1 多任务启动流程 多任务启动流程如下表所示 启动后以下各函数由上至下依次执行含义osKernelStart 启动内核vTaskStartScheduler 启动任务调度器xPortStartScheduler 启动调度器prv
  • Realsense d435i驱动安装、配置及校准

    写在前面 本文是在ubuntu20 04下安装 xff0c 其它版本大同小异 可能出现的问题 xff0c 主要由各自安装相关库版本不一致导致 xff0c 故问题不一 xff0c 但一般很好解决 xff0c 正常情况下不会出现 Intel R
  • Realsense d435i内参、外参标定

    使用工具code utils imu utils kalibr对Realsense d435i 内参 外参标定 本文介绍上述工具的安装 xff0c 及标定方法 一 code utils安装 1 建立工作空间 mkdir p calibrat
  • 从零完成slam实战,以Vins-Fusion为例

    写在前面 1 本文以vins fusion为例 xff0c 是因为其框架正统 简单清晰 xff0c 易于调试和后续改进 xff1b camera imu外参及同步时间td可实时估计 xff1b 已有融合gps方案且较为容易可添加融合其它传感
  • Vins-Fusion整体框架,数据流分析

    一 VINS Fusion VINS Fusion是一种基于优化的多传感器状态估计器 xff0c 可实现自主应用 xff08 无人机 汽车和AR VR xff09 的精确自我定位 VINS Fusion是VINS Mono的扩展 xff0c
  • Vins-Fusion初始化位姿——3D-2D:PNP求解当前帧位姿

    继上一篇博文Vins Fusion 外参camera imu 标定 xff0c 本文继续介绍Vins Fusion初始化时 xff0c 通过PNP求解当前帧位姿 一 3D 2D xff1a PNP PnP是求解3D到2D点对运动的估计 xf
  • ORB_SLAM3启动流程以stereo_inertial_realsense_D435i为例

    概述 ORB SLAM3 是第一个同时具备纯视觉 xff08 visual xff09 数据处理 视觉 43 惯性 xff08 visual inertial xff09 数据处理 和构建多地图 xff08 multi map xff09
  • BoW(词袋)模型详细介绍

    最近学习BoW模型 xff0c 将自己网上看到的资料及对论文的理解 xff0c 将BoW模型总结如下 xff01 BoW模型 Bag of words model BoW model 最早出现在自然语言处理 xff08 Natural La
  • Win10 VS Code + CMake STM32开发环境

    Win10 VS Code 43 CMake STM32开发环境 软件 软件安装与环境变量的配置不多讲 xff0c 这步都搞不定还是老老实实用MDK把 VS Codecmake 插件 c c 43 43 插件mingwgcc arm non
  • makefile 转 cmake STM32工程

    makefile 转 cmake STM32工程 STM32开发由MDK转到 vscode好久了 每次新建工程 xff0c stm32cubemx生成代码都要手动把makefile转到cmake xff0c 好烦 xff0c 特别一下小的频
  • STM32使用FreeRtos + C++

    编译环境 MDK5 25 gcc arm7 2 C文件不可包含CPP的头文件 C调用C 43 43 函数 在CPP文件内编写C函数 xff0c 头文件声明 头文件不可出现C 43 43 关键字 在main中调用此函数作为程序入口即可 voi
  • FreeRTOS系列|时间管理

    FreeRTOS时间管理 1 FreeRTOS延时函数 在使用FreeRTOS的过程中经常会在一个任务中使用延时函数对该任务延时 xff0c 当执行延时函数的时候就会进行任务切换 xff0c 并且此任务就会进入阻塞态 xff0c 直到延时完
  • 【Linux C与C++一线开发实践】之一 Linux概述与Linux C++开发

    Linux系统启动的基本过程 对于一台Linux系统来说 xff0c 用户按下开机按钮后 xff0c 一共要经历如下几个过程