Blog Feed

Manjaro上的Eclipse (Java)安装与配置(包括汉化)

本文内容建立在Manjaro (Arch Linux) 20.0.3系统上,安装时不进行手动编译。

安装

安装所需的必要软件包为yay,另外安装polipo可以解决网络无法连接的问题。安装配置方法参考文章《个人Manjaro配置记录》。

直接安装eclipse-java时会提示依赖不满足,因此先安装依赖。使用如下命令启用全局代理,并安装eclipse-common:

systemctl start polipo
yay -S eclipse-common

之后再安装eclipse-java:

yay -S eclipse-java

即可安装完成。

汉化

本部分参考了Eclipse Bable此页面

常规方案

安装完成之后,打开eclipse,打开Help-Install new software,将Babel网页页面上提供的链接输入“Work with”框,点击右侧“Add…”,输入适当的标题,如“Babel”,点击确定保存,在“Work with”下拉菜单中选择刚刚保存的网址,等待加载之后勾选对应的项目之后点击“Next”,一路进行到“Finish”即可。之后要关注右下角的进度条,双击可以查看细节,待到安装结束之后会提示重启,重启后即可正常使用中文版本。

如果在选中了适当的“Work with”项目却一直显示“Pending…”,则可以尝试取消勾选下方的“Show only the latest version of available software”等选项,稍等片刻应该即可恢复正常显示。

特殊方案

同样使用联网安装,但“Work with”的页面不同,使用了每日更新的测试Babel包。可在查看目录。选择需要的日期,直到进入链接形如

https://build.eclipse.org/technology/babel/babel_language_packs/NYYYYMMDD-NNNN/

的页面,复制网页中“Update site”的链接,粘贴进“Work with”框中,按照“常规方案”进行后续操作即可。

如果因为常规方案导致中文界面完全无法启动……

本部分参考了Eclipse的Arch Linux官方维基页面此页面

使用联网安装Babel出现问题一般不会影响英文界面的正常启动,因此关键在于让软件启动英文界面。使用如下命令编辑eclipse配置文件,位于/usr/lib/eclipse/eclipse.ini

sudo nano /usr/lib/eclipse/eclipse.ini

在文档末尾添加如下内容:

-Duser.language=en

保存退出之后重新打开Eclipse即可以英文界面启动,此时可以尝试“特殊方案”是否可行。

个人Manjaro配置记录

由于本文是个人配置记录,因此暂时略去了相关介绍内容,只关注具体的Manjaro下载安装与配置过程。

下列内容中标注星号(*)的内容可以根据实际需求跳过。

个人配置

Dell Inspiron 7572 (15.6寸)

操作系统: Arch Linux
KDE Plasma 版本: 5.19.4
KDE 框架版本: 5.72.0
Qt 版本: 5.15.0
内核版本: 5.6.15-1-MANJARO
操作系统类型: 64-位
处理器: 8 × Intel® Core™ i7-8550U CPU @ 1.80GHz
内存: 15.5 GiB 内存
图形处理器: Mesa Intel® UHD Graphics 620

上述内容来自安装并配置完成Manjaro之后的系统信息页面。其实图形处理器还有Nvidia GeForce MX150 (4GB显存)。

显然本人安装的是KDE版本。

下载镜像与烧录USB

下载Manjaro镜像

个人从Manjaro官网下载了KDE Plasma版本的Manjaro镜像。

使用qBittorrent搭配.torrent文件以获得更佳下载速度。

将Manjaro镜像烧录至U盘

下载.iso镜像之后,对于Windows系统用户,使用Rufus烧录U盘设备;对于Linux系统用户,使用dd命令进行烧录,参考此页面页面存档】。

对于UEFI启动设备,直接将,iso文件的内容拷贝至U盘是无效的。

安装Manjaro

安装前的准备工作

数据第一。进行一切涉及系统与数据的操作之前,一定要确保重要数据的安全,因此如果无法保证操作的安全性一定要先进行数据备份。

*Precautions

  • 用于安装回Windows系统的PE急救U盘。个人使用wepe
  • 其他系统的(安装)镜像。
  • 在进行安装之前备份现有数据到外置存储设备,如移动硬盘等。
  • 制作当前系统的快照等其他备份手段。

*为新系统调整硬盘空间

使用傲梅分区工具进行分区调整,为新系统空出使用空间,个人推荐至少50G (包括swap,EFI和根目录);实际是the more the better (尤其SSD,分区可用空间越小对硬盘损伤越大)。

调整BIOS设置

  • 关闭Secure Boot。
  • 将SATA设置从Raid On调整为AHCI。
    (此设置影响固态硬盘读取,前者情况下Linux系统无法正常检测固态硬盘)
  • 应用并退出。

使用烧录好的U盘安装Manjaro

Manjaro实时系统中,root密码为manjaro

插入烧录好的U盘,按F12进入启动设备列表,进入U盘启动项。在进入Live USB之前,先……

  • 将语言设置为“中文”。
  • 将时区设置为“Asia, Shanghai”。
  • 将驱动设置为“Nonfree”。

接下来就可以选择启动Manjaro实时系统了。进入系统之后关闭欢迎窗口,有条件的话连接网络,之后选择安装Manjaro,进行安装操作。

分盘时如果不存在EFI启动分区,则需要分出一个fat32分区,挂载/boot/efi,之后再分出swap分区和根目录即可,其中swap分区据说要和内存大小相近。

之后进行安装操作,等待结束之后重启计算机。

安装之后的Manjaro配置过程

Manjaro基于Arch Linux,使用pacman管理软件包。常用命令见(安装+卸载)和(卸载)。

HiDPI

多数HiDPI可以通过“系统设置→硬件>显示和监控→显示配置→全局缩放率”设置为125%完成,包括FireFox。

然而ThunderBird依然需要单独配置。about:config的进入方式为“ThunderBird→首选项→高级→常规→高级配置>配置编辑器→layout.css.devPixelsPerPx”设置为1.25。

配置软件源

软件源配置简直就是一劳永逸的事情。个人使用了清华的archlinux和archlinuxcn的镜像源,参考清华镜像源使用帮助archlinuxcn官方使用帮助archlinux官方的Mirrors维基页面

更换源之后需要下载keyring。使用以下命令:

sudo pacman -Syyu

当然,这里有必要提一句:archlinuxcn官方称不建议Arch Linux衍生发行版用户使用该源,并不会对由此造成的问题进行解决或负责。见FAQ部分,以下为原文:

Q: 我是 Manjaro 用户,我可以使用 [archlinuxcn] 仓库吗?
A: 不建议这样做。[archlinuxcn] 仓库只支持 Arch Linux,在衍生发行版上使用可能出现问题。如果您在非 Arch Linux 系统上使用 [archlinuxcn] 仓库遇到了问题,请不要将问题报告给我们。

2020年8月9日22.58引自 https://www.archlinuxcn.org/archlinux-cn-repo-and-mirror/ 的FAQ第三条。

然而我选择无视这个提醒……(:P)我们继续。

更换archlinux镜像源

在终端中运行以下内容:

sudo pacman-mirrors -i -c China -m rank

之后选择清华源选项即可。

更换archlinuxcn镜像源

在/etc/pacman.conf的文件末尾添加以下内容:

[archlinuxcn]
SigLevel = Optional TrustedOnly
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch

接下来运行以下命令来安装keyring。

sudo -S archlinuxcn-keyring

运行以下命令获取镜像源列表。

sudo pacman -S archlinuxcn-mirrorlist-git

更新系统

一旦配置好软件源之后,二话不说,运行以下命令更新系统和软件。

sudo pacman -Syu

系统驱动与语言包

个人选择使用闭源驱动(毕竟稳定性摆着)。

打开“系统设置”,在“Manjaro”分类进入“硬件设定”选项,选择“Auto Install Proprietary Driver”。

在“Manjaro”分类进入“语言包”选项,在“可用的语言包”选项卡点击“已安装的语言包”(可能是官方翻译有误……)。

个人Konsole配置方案

外观:白底黑字,模糊背景,透明度30%,字体Menlo 14pt。

*更换Zsh

参考了此页面

sudo pacman -Syy zsh
sudo nano /etc/passwd

将指定用户的shell路径替换为/usr/bin/zsh,个人使用默认主题。

IME

Rime

No Sogou。

本来是准备使用搜狗的,但是一想起来搜狗那个尿性,我还是决定拾起Rime。

安装IBus-Rime,并通过“东风破”安装输入方案,使用如下命令:

sudo pacman -Syy ibus-rime
curl -fsSL https://git.io/rime-install | bash

接下来需要配置IBus,本部分参考了此页面Arch Linux官方的Rime维基页面

使用如下命令分别编辑~/.bashrc和~/.xprofile:

nano ~/.bashrc
nano ~/.xprofile

向其中加入如下配置:

export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus
ibus-daemon -x -d

保存并退出,重启计算机。IBus将自动运行。此时可以在IBus首选项中添加Rime了。

Linux下的IBus-Rime不支持更换皮肤。如果需要对Rime进行定制,可以参考Rime官方维基页面。我后续也可能整理一份相对“简化”的Rime笔记(虽然本人并没有切身定制过..本来想自己定制结果看了一夜定制指南结果因为感觉太难所以放弃了orz)。个人发现并在使用中的现成的定制指南,来源见页面存档】。

日语(ibus-anthy)

使用如下命令安装:

sudo pacman -Syy ibus-anthy

如果之前配置都做完了,那么安装并重启之后,在IBus中添加即可使用。

科学上网

由于之前尝试系统时无意中发现了一个好用的软件——Qv2rayGithub页面】,所以现在我已经抛弃了过时的electron-SSR,选择了这个all in one的软件(本体支持v2ray,安装相应插件之后支持SSR,SS,Trojan等,插件安装参考官方指南)。

这里顺便记录一下插件的安装目录为~/.config/qv2ray/plugins/

安装使用如下命令:

sudo pacman -Syy qv2ray

补充

经过实践检验,实际使用的时候代理这一部分有很多坑,几乎是用一款应用程序需要上网查找一次解决方案。因此特整理于此。本方法中使用了相对使用简单的proxychains_ng

首先要在Qv2ray中开启“系统代理”:在托盘上右键→“系统代理”→“启用系统代理”。

其次是要关注Qv2ray首选项中“入站设置”的监听地址和端口。

安装proxychains_ng:

sudo pacman -Syy proxychains

安装之后修改配置文件:

nano /etc/proxychains.conf

在配置文件最后,将默认的socks4配置注释掉,添加Qv2ray的socks5监听设置,最后的效果如下(Qv2ray的默认socks5监听设置为socks5://127.0.0.1:1089):

[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
# socks4 	127.0.0.1 9050
socks5 	127.0.0.1 1089

然而保存之后再使用proxychains运行yay,curl等依然会出现无法下载或404的错误。这时,收到该页面启发,打开Qv2ray入站设置的“嗅探”选项,即可正常使用,原因未知。方法:打开Qv2ray首选项,在“入站设置”选项卡勾选“SOCKS设置”与“HTTP设置”下的“嗅探”选框,“确定”保存。

之后需要使用时,输入如下命令(以makepkg为例):(-q选项可以屏蔽proxychains输出,建议选用)

proxychains -q makepkg -si

另外设置环境变量、git的代理有专门的命令,参考Qv2ray官方指南该页面。归纳大致如下:

设置环境变量(未开启身份验证时):

export HTTP_PROXY="http://127.0.0.1:8889"
export HTTPS_PROXY="http://127.0.0.1:8889"

设置git代理(未开启身份验证时):

git config --global http.proxy http://127.0.0.1:8889
git config --global https.proxy http://127.0.0.1:8889

git config --global http.proxy 'socks5://127.0.0.1:1089'
git config --global https.proxy 'socks5://127.0.0.1:1089'

顺便说句,网上的配置curl啊,makepkg啊的代理设置教程根本不管用(当然也有可能是我本人太笨),所以还是老老实实用了proxychains…

安装yay并解决yay下载速度问题

参考了该页面该页面

使用如下代码安装yay:

git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si

使用polipo全局代理:

yay -S polipo
sudo cp /etc/polipo/config.sample /etc/polipo/config
sudo vim /etc/polipo/config

取消注释并改写为以下两行:(数值使用了Qv2ray的socks5端口)

socksParentProxy = "127.0.0.1:1089"
socksProxyType = socks5

使用时,用以下命令开启polipo,之后再使用yay

systemctl start polipo

关闭polipo:(将stop替换为disable以禁用polipo)

systemctl stop polipo

Chrome

按顺序,在前面都配置完成之后再安装Chrome,这样就可以登录Google帐号同步了。

安装使用如下命令:

sudo pacman -Syy google-chrome

美化

搞了这么多次Linux系统安装,折腾来折腾去,总结出两点不能碰的坑:一个是wine,一个就是美化……

话虽如此..我还是折腾了起来,并且乐此不疲,真是可悲orz

美化过程部分参考了该页面

图标与光标

个人并没有更换系统图标,使用的是预装的“微风2”。光标使用的Adwaita。

Plasma部件

内置部件看情况添加,不再赘述。

额外安装的Plasma部件有:

另外安装了kcm-colorfulBreezeBlurred,使窗口和菜单栏部分模糊透明。使用如下命令进行安装。

首先安装kcm-colorful,使用如下命令(需要提前添加archlinuxcn源):

sudo pacman -S kcm-colorful-git

接下来安装BreezeBlurred,首先安装依赖:

sudo pacman -S kdecoration qt5-declarative qt5-x11extras kcoreaddons kguiaddons kconfigwidgets kwindowsystem fftw cmake extra-cmake-modules

接下来使用如下命令进行安装:

git clone https://github.com/alex47/BreezeBlurred
cd BreezeBlurred
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DKDE_INSTALL_LIBDIR=lib -DBUILD_TESTING=OFF -DKDE_INSTALL_USE_QT_SYS_PATHS=ON
sudo make install
kwin_x11 --replace &

安装之后进行配置,参考kcm-colorful的readme文件,此处根据Manjaro进行了调整:

  1. 打开“系统设置”,在“外观”分类进入“Plasma 样式”选项,选择“Colorful”。
  2. 在“外观”分类进入“应用程序风格”选项,再进入“窗口装饰”选项,在“主题”选项卡中选择“微风Blurred”。(“标题栏按钮”选项卡也可以根据喜好自行配置)
  3. 点击“微风Blurred”预览图右下角的配置按钮,进行如下配置:
    • “常规”选项卡中:
      • *“按钮大小”选择“小”。
      • *勾选“在关闭按钮周围绘制圆圈”。
      • *勾选“为无边框窗口添加缩放柄”。
      • “Opacity”(不透明度)设置为“30%”。
    • *“阴影”选项卡中:
      • “大小”选择“很大”。
  4. 在“工作区”分类进入“工作空间行为”选项,再进入“桌面特效”选项,在“外观”分类勾选“模糊”和“背景对比度”选项。

字体

本部分参考了此页面

首先安装所需要的字体。如果是搭配Windows的双系统可以直接拷贝系统文件夹中的Fonts文件夹,在Manjaro的某个目录中粘贴。使用如下命令进行安装:

sudo mkdir /usr/share/fonts/winfonts/
sudo cp win_font_path/* /usr/share/fonts/winfonts/
cd /usr/share/fonts/winfonts/
rm *.fon
sudo mkfontscale
sudo mkfontdir
fc-cache -fv

对于.ttc字体集合,需要在“系统设置→外观>字体→字体管理→从文件安装…”进行安装。其他具体安装方式可以参考Arch Linux官方的字体维基页面。

设法使用Apple系字体,利用此页面提供的方法。(但是其中苹方字体的名称似乎写成了“.萍方”??)

先使用如下命令下载所需文件:

git clone https://github.com/xMuu/arch-kde-fontconfig.git

安装所需字体后,编辑该目录下的64-language-selector-prefer.conf文件(可根据情况对源文件进行备份),本人的配置如下,差异请自行比对。(需要提前安装Menlo字体)

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <alias>
    <family>sans-serif</family>
    <prefer>
      <family>SF Pro Text</family>
      <family>PingFang SC</family>
      <family>PingFang HK</family>
      <family>PingFang TC</family>
    </prefer>
  </alias>
  <alias>
    <family>monospace</family>
    <prefer>
      <family>Menlo</family>
      <family>PingFang SC</family>
      <family>PingFang HK</family>
      <family>PingFang TC</family>
    </prefer>
  </alias>
  <alias>
    <family>serif</family>
    <prefer>
      <family>Source Serif Pro</family>
      <family>Source Han Serif CN</family>
      <family>Noto Serif CJK SC</family>
      <family>Noto Serif CJK TC</family>
    </prefer>
  </alias>
</fontconfig>

修改之后即可进行如下操作:

cd arch-kde-fontconfig
sudo mv 64-language-selector-prefer.conf 64-language-selector-prefer.old
sudo cp 64-language-selector-prefer.conf /etc/fonts/conf.avail/
sudo ln -s /etc/fonts/conf.avail/64-language-selector-prefer.conf /etc/fonts/conf.d/64-language-selector-prefer.conf
sudo fc-cache -fv

之后就可以在系统设置中调整字体了,可以参考上述Github页面。

其他推荐字体来源:Github页面1,Github页面2。

安装思源字体、文泉驿字体、DejaVu字体、Noto字体:

sudo pacman -S wqy-microhei wqy-bitmapfont wqy-zenhei wqy-microhei-lite
sudo pacman -S adobe-source-han-sans-cn-fonts adobe-source-han-serif-cn-fonts adobe-source-han-mono-cn-fonts
sudo pacman -S ttf-dejavu
sudo pacman -S noto-fonts noto-fonts-extra noto-fonts-emoji noto-fonts-cjk

其他美化

主要是“桌面特效”这一项,选项记不住所以这里记录一下。

  • 工作区>工作空间行为:
    • 常规行为→点击行为:双击打开文件和文件夹
    • 屏幕边缘→全部取消;四分拼接20%
    • 桌面特效→外观除破碎、缩略图置边、触摸点、飘落、鼠标标记、压扁全勾选
  • 工作区>开机与关机→SDDM>主题→Sugar Candy
  • ……

音乐

本人使用Apple Music,所以直接https://music.apple.com/
(说起来现在新推出了一个beta版本,UI看起来不错哦)

游戏

使用如下命令安装Steam:

sudo pacman -Syy steam

其他杂项

卸载Gwenview,这个屑软件依赖版本太高了,以至于需要unstable版本系统才能提供,导致无法使用。Manjaro系统更新之后该问题得以解决。当然如果不愿使用Gwenview,也可以参考Arch Linux官方维基页面选择喜欢的应用程序(不仅包括图像查看器)。

可以使用如下命令卸载Gwenview,安装GPicView (上古界面+反人类操作预警,并不推荐):(使用pacman -Rsc时一定要关注卸载了哪些软件包,因为它会自动地卸载相关于软件包的无用依赖)

sudo pacman -Rsc gwenview
sudo pacman -Syy gpicview

视频等可以使用VLC播放器:

sudo -Syy vlc

*事后急救汇总

拯救grub

本人安装的是双系统(Windows 10 + Manjaro),安装完Manjaro之后进了Windows,结果抽风,把Manjaro的EFI(FAT32)盘给隐藏了(Windows和Manjaro没有安装在同一块硬盘上),再开机的时候就进入不了Manjaro了,惊慌之下赶紧进入Windows取消隐藏Manjaro的EFI盘,重启依然不管用。因此迫不得已琢磨起来该怎么修复。

显然问题不会出现在其他分区上,只能是FAT32分区上,或者FAT32分区和根目录的联系上(??不清楚有这种东西吗)。我当作前者处理。

处理方式参考了此页面此页面Manjaro官方的恢复GRUB引导维基页面。维基页面还包含了其他可能出现的问题以及解决方法。

使用Manjaro的实时系统U盘,进入实时系统之后打开终端,使用lsblk -f查看分区分布,通过挂载点特征、分区大小等信息确定各个分区的编号。接下来使用如下命令给出chroot选项:

sudo manjaro-chroot -a

一般情况下,在漫长等待之后会收到仅列出第0项的“Detected Systems”列表,此时……输入1,回车。

接下来挂载对应分区,使用如下命令:

sudo mount /dev/sdxy /mnt
sudo mount /dev/sdmn /mnt/boot
sudo mount /dev/sdpq /mnt/boot/efi 

挂载结束之后,安装mtools和os-prober。(如果可能的话)

sudo pacman -S mtools os-prober

之后切换根目录:

cd /mnt
chroot ./

重装GRUB:

sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=manjaro --recheck

更新GRUB:(或者直接grub-mkconfig)

sudo grub-mkconfig -o /boot/grub/grub.cfg

至于修复好之后每每开机都会显示的Welcome to GRUB!,我实在是懒得搞了orz,想了解或者折腾的可以参考此页面

无损扩大分区空间(需要Windows系统)

所需工具

  • 安装了Manjaro实时系统的U盘(Manjaro安装U盘)。
  • Disk Genius和/或傲梅分区助手。

步骤

该部分参考了此页面

  • 使用熟悉的方式分出用于合并至Linux分区的空间。
  • 烧录Manjaro实时系统至U盘。方法:Windows使用Rufuus工具,Linux使用dd命令。具体参考前文。
  • 在Windows下(包括PE)运行驱动精灵,将ext4分区前后紧贴的分区搬移至空闲空间首尾位置,为ext4附近留出空间。
  • 在Manjaro实时系统中,使用命令lsblk查看希望扩展的分区编号,以/dev/sda2为例,之后使用如下命令来检查分区内是否有错、能否进行优化整理:
e2fsck -f /dev/sda2
  • 修复完之后,使用Manjaro提供的系统工具“KDE 分区管理”进行扩容操作。操作完成后再次使用e2fsck -f /dev/sda2命令查错。至此,分区无损扩容完成。

*另外值得注意的是,如果使用Disk Genius进行了删除Linux-swap分区并重建的操作,则需要在Manjaro实时系统中(利用“KDE 分区管理等工具”对Disk Genius生成的Linux-swap分区重新格式化,否则系统无法识别,不能启动。

未尽事宜

  • iOS设备管理。(预计无解)
  • Better (fxcking) Tencent software experience。(预计无解+1)
  • And more……

为Dell Inspiron 7572安装Windows 7 (64位)

文章所讨论内容建立在如下硬件基础上,且仅讨论64位系统安装。
计算机型号:Dell Inspiron 7572
CPU:Intel Core i7-8550U
核心显卡:Intel UHD Graphics 620
独立显卡:Nvidia GeForce MX150 4G
固态硬盘:NVMe HP SSD EX900 250
无线网卡:Qualcomm QCA61x4A 802.11ac

请注意,文章中的“访问码”需要使用鼠标选中查看。

在安装新系统前,建议养成备份重要文件的好习惯。

安装综述

Windows 7是Microsoft发布于2009年的计算机操作系统,并已于2020年左右停止更新与支持。而Intel自第7代CPU开始已经不再支持Windows 10之前的Windows操作系统了。Windows 7未内置USB 3.0及以后版本的驱动程序、NVMe固态硬盘的驱动程序以及一部分无线网卡的驱动程序,它甚至未直接提供UEFI的启动文件。更不幸的是,HP EX900这款固态硬盘不像Intel的系列固态硬盘;它在HP官网上并无对应驱动程序。因此,要在使用UEFI+GPT方式启动的新电脑上安装Windows 7,USB 3.0驱动、固态硬盘驱动、UEFI启动是需要攻克的难题,另外可能还需要提前准备好无线网卡驱动。

安装前准备

  1. 下载Windows 7 x64的原版镜像,建议选择集成Service Pack 1 (SP1)的镜像,以便减少后期消耗在系统更新上的精力。可以选择使用MSDN I Tell You进行下载(ed2k)。下载后将其存放在硬盘上即可。
  2. 下载PE系统安装器,为U盘安装PE系统。个人推荐使用微PE工具箱,也可以自行选择其他平台。主要目的是保证能够使用其中的WinNTSetup程序。
  3. 下载Dell专用该型号无线网卡驱动(.exe)。此处链接使用了天翼云盘。访问码:rt0c。也可以在驱动管理软件中或Dell支持官网中自行寻找驱动进行下载。
  4. 下载Intel官方USB 3.0驱动。下载Dell知识库中使用的USB 3.0驱动与NVMe驱动注入程序,最后之后用到NVMe驱动部分。
  5. 下载修改版Intel 8代CPU核显驱动程序。也可以选择使用天翼网盘。访问码:w2ax
  6. 将上述驱动程序放置在同一个单独的文件夹下,例如某个命名为“drivers”的文件夹。这个文件夹下至少应该包含这些内容:
    1. 第4步中下载的USB 3.0驱动文件夹(/Intel(R)_USB_3.0_eXtensible_Host_Controller_Driver_5.0.4.43_v2/Drivers);
    2. 第4步中下载的Win7_Boot文件夹的IRST部分(/Win7_Boot/Drivers/IRST)。

BIOS设置

开机时按下F2进入计算机的BIOS设置,将“Secure Boot”关闭,并确保将SATA访问模式设置为“Raid On”。将更改保存后退出重启。

安装Windows 7

在设置了BIOS之后,将U盘插入计算机。开机时按下F12进入启动选择页面,选择USB设备选项,进入PE系统。

在PE系统内进行分区操作,并在DiskGenius内为计算机的EFI分区(ESP)分配盘符。

打开PE系统内置的WinNTSetup程序。根据PE系统提供来源的不同,该程序可能在桌面或开始菜单中被命名为类似于“Windows安装”的名称。安装来源选择之前下载的Windows 7镜像文件(.iso),引导分区为之前挂载的EFI分区,安装分区为自行划分的分区(若希望全新安装,可进行格式化操作)。注入驱动的文件夹选择前文提到的“drivers”文件夹。选择安装版本,并根据需要进行“优化调整”配置之后,点击“开始安装”按钮,勾选“添加已有Windows版本选项”。点击“开始”按钮,即可自动复制Windows 7系统文件。

复制结束之后,将计算机重启,即可进入Windows 7安装向导界面。对安装向导进行相关配置之后,即可进入桌面。

为Windows 7继续安装驱动程序

当安装Windows 7成功后,首先调整屏幕分辨率和缩放比例。一般调整为1920×1080分辨率,125%缩放比例。

接下来安装无线网卡驱动程序,打开之前下载的网卡驱动安装文件进行安装即可。

之后安装Intel 8代CPU的核显驱动程序,打开之前下载的核显驱动程序安装文件,将文件夹解压之后,直接运行“setup.exe”即可。由于下载的安装文件为.rar格式,因此可能需要提前安装压缩软件。个人推荐使用WinRAR,如果担心广告,使用繁体中文版并进行注册即可解决。注册方法可以自行搜索。安装结束后默认勾选了评级与Aero桌面选项,若不进行更改,则重启后初次进入系统时,桌面会保持黑屏,仅鼠标可见。此时按下Control-Shift-Escape调出Windows任务管理器窗口后,即可恢复正常显示,并且此时Aero效果已经打开。

在安装了核显驱动之后,才可以安装Nvidia GeForce独显驱动。直接在GeForce官网上进行下载并安装即可。如果安装出现蓝屏,也可以先安装该版本驱动程序,它支持Windows 7。也可以选择使用天翼云盘下载。访问码:god9。之后再进行升级。

善后处理

  • 打开Windows Update,进行系统更新。
  • 激活Windows。
  • 安装其他浏览器(如Google Chrome),并用它打开此页面下载并更新Internet Explorer 8至Intrnet Explorer 11。此操作建议在进行Windows Update更新之后再进行。
  • 继续安装其他驱动。若使用Dell SupportAssist或Dell Update等,则它(们)不能提供很多有用的驱动程序,因为Dell Inspiron 7572机型在Dell支持官网上本身不支持Windows 10 x64之前的Windows操作系统,也没有相应驱动。

未尽事宜

  • 触摸板驱动等其他驱动。

HIT-ICS2020大作业:程序人生-Hello’s P2P

摘要:hello程序是几乎所有人学习计算机编程知识的第一站,然而其生成结果的具体过程并非人尽皆知。本文放眼hello的一生,探究在Linux操作系统下,它从诞生到在内存中的消亡的短暂而又漫长的过程中所经历的种种考验,深入理解它的P2P、O2O历程,以此完成对计算机系统课程的整体复习与深入理解。

关键词:hello程序;计算机系统;预处理;编译;汇编;链接;虚拟内存;异常处理;IO

第1章 概述

1.1 Hello简介

hello的C程序被编写出来之后,经历预处理器、编译器、汇编器、链接器的重重考验,最终生成可执行目标程序。用户在shell中输入相应的指令之后,shell便进行调用fork函数,为其创建子进程。由此,hello经历了从程序(program)到进程(process)的P2P过程。

在执行可执行目标程序hello之前,系统并未为其分配内存。当用户执行它之后,内核为其映射出虚拟内存,并将其载入物理内存。待其运行结束,shell父进程将hello进程回收,内核将相关数据结构删除,hello在内存中所占的空间重新清零。由此,hello经历了从零(0)到零(0)的O2O过程。

1.2 环境与工具

硬件环境:Intel Core i7-8550U x64 CPU;16G RAM;256G SSD;1T HDD
软件环境:Windows 10(64位);VMware Workstation 15;Ubuntu 18.04 LTS(64位)
开发与调试工具:cpp,gcc,ld,记事本,gedit,objdump,edb,terminal,readelf

1.3 中间结果

hello.i                 hello.c经预处理后生成的文件
hello.s                hello.i经编译后生成的文件
hello.o                hello.s经汇编后生成的文件
hello.dis             hello.o经反汇编后重定向到的文件
hello                   hello.o经链接后生成的文件
hello.dis2           hello经反汇编后重定向到的文件

1.4 本章小结

本章对hello一生中完成的P2P过程与O2O过程进行梳理概括,并未接下来对hello一生的探究做了准备。

第2章 预处理

2.1 预处理的概念与作用

概念:预处理器(cpp等)根据以字符#开头的命令,修改原始的C程序。生成另一个以.i为文件扩展名的C程序。

作用:对于原始C程序中的以字符#开头的命令:导入需要使用的库函数;替换宏定义;进行条件编译。

2.2在Ubuntu下预处理的命令

cpp hello.c > hello.i

2.3 Hello的预处理结果解析

预处理结果如图所示:

由图可以看出,在进行预处理之后,原本短短的23行代码被扩充为3113行代码,其中的注释内容不予保留,main函数直到3100行才出现,之前的内容由“#include”开头的内容中指定的库文件内容进行递归替换。

2.4 本章小结

预处理是C语言程序迈向进程的第一步,在这个过程中,预处理器对原始C程序文件进行相关替换与改写,最后生成扩展名为.i的新的C语言程序。

第3章 编译

3.1 编译的概念与作用

概念:编译器(ccl等)将.i文本文件翻译成.s文本文件,它包含一个汇编语言程序。

作用:对替换后的C语言程序进行“翻译”,将其编译成汇编语言,做好后续转换为二进制数的准备。

3.2 在Ubuntu下编译的命令

gcc -m64 -Og -no-pie -fno-PIC hello.i -S -o hello.s

3.3 Hello的编译结果解析

下图是hello.s的内容。

3.3.1 对数据/数据结构的处理

3.3.1.1 字符串

“printf”内的两个字符串“用法: Hello 学号 姓名 秒数!\n”和“Hello %s %s\n”分别存在了.rodata段中的.LC0.LC1中。使用时直接将其作为立即数。

3.3.1.2 数组

在本程序中,使用了系统的数组argv[]argv是指向char型变量指针的指针,且第一个参数是程序名本身。根据指针的长度为8字节和汇编程序可以推测出,argv在寄存器rsi中被取用(之后复制给了寄存器rbp)。使用argv[n]时,对rbp内容进行偏移地址计算后取用(8n(%rbp))。

3.3.1.3 局部变量

本程序中的局部变量为iargc。变量i没有被赋予初值,在汇编程序中被寄存器ebx代替。变量argc的内容被保存在寄存器edi中。

3.3.2 对赋值的处理

使用mov系列指令。本程序中for循环内的“i=0”即被编译成

movl	$0, %ebx

3.3.3 对算术操作的处理

本程序中在for循环内包含有“i++”操作,它被编译成

addl	$1, %ebx

3.3.4 对关系运算的处理

本程序中的if条件判断中使用了“argc!=4”,它被编译成

cmpl	$4, %edi
jne	.L6

for循环中使用了“i<8”,它被编译成

cmpl	$7, %ebx
jle	.L3

3.3.5 对控制转移的处理

本程序中的if(argc!=4)条件判断结构通过简单的cmp系列指令与条件跳转指令完成。它被编译成

cmpl	$4, %edi
jne	.L6

其中汇编程序内.L6标号后的内容对应着C程序中的if成立执行内容。.L6标号内容放在了后面的某个jmp指令之后。

本程序中的for循环结构通过cmp系列指令与条件跳转指令完成。它被编译成

	movl	$0, %ebx
	jmp	.L2
	;...中间代码
.L3:
	;...for循环体汇编代码
	addl	$1, %ebx
.L2:
	cmpl	$7, %ebx
	jle	.L3

可见for循环的在汇编语言中的框架如此,易知循环一共进行8次。

3.3.6 对函数操作的处理

使用call指令和ret指令。程序中调用了函数printfexitsleepatoigetchar均使用了call指令,分别被编译为

call puts
call exit
call printf
call atoi
call sleep
call getchar

调用函数时,均通过寄存器edi传值。

main函数结尾的return 0,被编译成

.cfi_def_cfa_offset 24
popq	%rbx
.cfi_def_cfa_offset 16
popq	%rbp
.cfi_def_cfa_offset 8
ret
.cfi_endproc

3.4 本章小结

本章讲述了扩充后的C程序被编译器编译为汇编语言程序时几种数据与操作编译的主要过程。在编译阶段,编译器根据特定的算法与优化选项,将C程序进行优化合并,对其结构进行调整,“翻译”成汇编语言程序,为下一阶段汇编器的翻译做好准备。

第4章 汇编

4.1 汇编的概念与作用

概念:汇编器(as等)将汇编源程序(.s文本文件)翻译成机器语言指令,把这些指令打包成可重定位目标程序,并将结果保存在.o目标文件中。它是一种二进制文件,无法用文本编辑器正常打开。

作用:通过汇编器(汇编程序)将汇编源程序汇编成二进制可重定位目标程序,为下一步的链接做准备。

4.2 在Ubuntu下汇编的命令

gcc -m64 -Og -no-pie -fno-PIC -c hello.s -o hello.o

4.3 可重定位目标elf格式

分别运行以下指令

readelf -h hello.o
readelf -S hello.o
readelf -S -W hello.o
readelf -r hello.o

可得以下结果

由图可知,hello.o中包含.text节,.rela.text节,.rodata节,.comment节,.eh_frame节,.rela.eh_frame节,.symtab节,.strtab节,.shstrtab节。

ELF头以一个16字节的序列开始(即Magic),这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位,可执行或者共享的),机器类型(如x86-64)、节头部表的文件偏移,以及节头部表中条目的大小和数量。

节头部表描述了其中条目的大小和位置等。

其中典型节的含义:

.text:已编译程序的机器代码;
.rodata:只读数据,如printf语句中的格式串和switch语句的跳转表;
.symtab:存放在程序中定义和引用函数和全局变量信息的符号表;
.rel.text(此处结果为.rela.text):重定位节,保存目标文件与其他文件组合时需要修改位置的.text节中的列表;
.strtab:一个字符串表,内容包括.symtab.debug节中的符号表;
.rela.eh_frame:存放.eh_frame的重定位信息。

4.4 Hello.o的结果解析

使用指令objdump -d -r hello.o > hello.dis到上述反汇编文件hello.dis。将其与hello.s进行对比,可以发现main函数的总体结构没有发生变化,基本可以一一对应。主要区别在于:

1. 分支转移方面,使用偏移地址代替了标号。原因在于标号属于提示性信息,在汇编过程中,不会被保留,执行时根据给出的地址进行相应的跳转。

2. 对.rodata中的字符串取用方面,在编译后的文本文件中,将标号作为立即数直接使用,而在反汇编文件中,使用的是$0x0,并在下方给出重定位信息,对字符串进行访问。

3. 函数调用方面,在反汇编文件中使用了偏移地址代替待调用函数名,并在下方给出了.rela.text中的重定位信息。

4.5 本章小结

本章主要分析了汇编器对汇编源程序的汇编操作结果。汇编器将汇编源程序“翻译”成二进制文件,形成ELF文件,并在头部保留相关信息,便于后续链接操作的进行。对二进制文件进行反汇编,可以发现,程序的大体结构得到保留,但是与之前的汇编源程序之间依然有细微的差别。

第5章 链接

5.1 链接的概念与作用

概念:链接器(ld等)将多个有调用关系的.o程序进行合并,生成一个可执行目标文件。

作用:对.o程序中需要替换的地方进行替换,并重新生成完整的可执行文件。链接使得分离编译成为可能。

5.2 在Ubuntu下链接的命令

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o hello.o /usr/lib/x86_64-linux-gnu/libc.so /usr/lib/x86_64-linux-gnu/crtn.o -o hello

5.3 可执行目标文件hello的格式

运行命令readelf -S -W hello,得图

如上图所示,易得各段名称、类型、起始地址、偏移地址和大小等信息。

5.4 hello的虚拟地址空间

    使用edb加载hello后,发现程序加载地址范围为0x400000~0x4007b3,即从elf开头到.eh_frame段。根据readelf输出的信息,可以在edb的Data Dump中找到对应的数据。下举两例,其他段同理。

由5.3节图,.interp节:0x400200~0x40021c,在edb中的Data Dump见下图;

.text节:0x400550~0x400661,在edb中的Data Dump见下图。

5.5 链接的重定位过程分析

运行指令`objdump -d -r hello > hello.dis2,得到hello的反汇编程序文本hello.dis2,如下图

通过与hello.o的反汇编程序hello.dis比较,可以发现hello的反汇编程序中的地址已经被装配,并且插入了其他库函数内容。

由于在链接时指定了库/lib64/ld-linux-x86-64.so.2,/usr/lib/x86_64-linux-gnu/crt1.o,/usr/lib/x86_64-linux-gnu/crti.o,/usr/lib/x86_64-linux-gnu/libc.so,/usr/lib/x86_64-linux-gnu/crtn.o,故hello.o程序中的printfexitsleepatoigetchar函数均被替换,另外还加入了启动、终止相关函数,使程序能够被启动与终止。

根据hello.o中的重定位项目,可以推测出链接器在遇到相应的.plt重定位之前,需要使用的库函数已经被放入了.plt中,故链接器只需要将相应的地址填写到.text节中需要进行替换的位置即可。

.rodata节中的两个字符串的引用过程与之类似,链接器将.rodata中需要调用的内容的地址填入.text中的相应位置即可。

5.6 hello的执行流程

从开始加载到程序终止的整个过程中,调用的所有子程序名与地址如下:

ld-2.27.so!_start                                                        0x7fa3:1e3a5090
ld-2.27.so!_dl_start                                                   0x7f5b:021ecea0
ld-2.27.so!_dl_start_user                                           0x7fa3:1e3a5098
ld-2.27.so!_dl_init                                                     0x7f61:963c9630
libc-2.27.so!_init                                                       0x7fdf:0d1fc920
libc-2.27.so!_dl_vdso_vsym                                     0x7fdf:0d3423b0
ld-2.27.so!_dl_lookup_symbol_x                             0x7fdf:0d5d70b0
ld-2.27.so!do_lookup_x                                            0x7fdf:0d5d6240
ld-2.27.so!strcmp                                                      0x7fdf:0d5e9360
libc-2.27.so!__init_misc                                           0x7fdf:0d2fc6f0
libc-2.27.so!@plt                                                      0x7fdf:0d1fc270
libc-2.27.so@__strrchr_avx2                                    0x7fdf:0d3693c0
libc-2.27.so!__ctype_init                                          0x7f2d:652178f0
libc-2.27.so!init_cacheinfo                                       0x7f2d:65208470
libc-2.27.so!handle_intel.constprop.1                       0x7f2d:652a2e80
libc-2.27.so!intel_check_word.isra.0                        0x7f2d:652a2b80
hello!_start                                                                0x400550
libc-2.27.so!_libc_start_main                                   0x7fb0:ac471ab0
libc-2.27.so!__cxa_atexit                                          0x7fb0:ac493430
libc-2.27.so!__new_exitfn                                        0x7fb0:ac493220
hello!__libc_csu_init                                                       0x4005f0
hello!_init                                                                  0x4004c0
libc-2.27.so!_setjump                                               0x7fb0!ac48ec10
libc-2.27.so!_sigsetjump                                           0x7fb0!ac48eb70
libc-2.27.so!__sigjump_save                                    0x7fb0!ac48ebd0
hello!main                                                                 0x400582
hello!puts@plt                                                           0x4004f0
hello!.plt                                                                    0x4004e0
ld-2.27.so!_dl_runtime_resolve_xsavec                   0x7f2d:655ef750
ld-2.27.so!_dl_fixup                                                  0x7f2d:655e7df0
libc-2.27.so!__GI__IO_file_xsputn                          0x7f2d:65272930
libc-2.27.so!__GI__IO_file_overflow                      0x7f2d:65274330
libc-2.27.so!__GI__IO_doakkocbuf                         0x7f2d:65275300
libc-2.27.so!__GI__IO_doallocate                           0x7f2d:65265100
libc-2.27.so!__GI__IO_file_stat                               0x7f2d:65272180
libc-2.27.so!_fxstat                                                   0x7f2d:652f67b0
libc-2.27.so!.plt+0x2f0                                             0x7f2d:652082c0
libc-2.27.so!malloc                                                   0x7f2d:6527e071
libc-2.27.so!malloc_hook_ini                                   0x7f2d:6527da40
libc-2.27.so!ptmalloc_int.part.0                                0x7f2d:652783e0
libc-2.27.so!_dl_addr                                                0x7f2d:6534cfb0
ld-2.27.so!rtld_lock_default_lock_recursive            0x7f2d:655d90e0
ld-2.27.so!_dl_dind_dso_for_object                         0x7f2d:655ec640
……(此列表不完整)

其中主要函数调用如下:

ld-2.27.so!_start                                                        0x7fa3:1e3a5090
ld-2.27.so!_dl_start                                                   0x7f5b:021ecea0
ld-2.27.so!_dl_start_user                                           0x7fa3:1e3a5098
ld-2.27.so!_dl_init                                                     0x7f61:963c9630
hello!_start                                                                0x400550
libc.2.27.so!__libc_start_main                                  0x7f19:b29f8ab0
libc-2.27.so!__cxa_atexit                                          0x7fb0:ac493430
hello!__libc_csu_init                                                       0x4005f0
hello!_init                                                                  0x4004c0
libc-2.27.so!_setjump                                               0x7fb0!ac48ec10
hello!main                                                                 0x400582
hello!puts@plt                                                           0x4004f0
hello!exit@plt                                                           0x400530
hello!pritf@plt                                                          0x400500
hello!atoi@plt                                                           0x400520
hello!sleep@plt                                                         0x400540
hello!getchar@plt                                                     0x400510
libc-2.27.so!exit                                                        0x7f59:24544120
libc-2.27.so!__run_exit_handlers                             0x7fc5:aa515ed0

5.7 Hello的动态链接分析

调用动态链接共享库函数时,链接器会使用延迟绑定策略,利用GOT和PLT两种数据结构完成对库函数的动态链接。

如图为GOT在dl_init前的内容:

下图为GOT在dl_init之后的内容:

其中GOT[0]和GOT[1]包含动态链接器在解析函数地址时会使用的信息,GOT[2]是动态链接器在ld-linux.so模块中的入口点。其余的每个条目对应于一个被调用的函数,有一个相匹配的PLT条目。

5.8 本章小结

在本章中进行了程序的链接操作,链接包括静态链接和动态链接。并对链接后的程序运行进行了跟踪分析。

第6章 hello进程管理

6.1 进程的概念与作用

概念:一个执行中的程序的实例。

作用:提供给应用程序抽象:一个独立的逻辑控制流、一个私有的地址空间。

6.2 简述壳Shell-bash的作用与处理流程

作用:shell是一个交互型的应用级程序,它代表用户运行其他程序。

处理流程:(读步骤)读取来自用户的一个命令行;(求值步骤)解析命令行;代表用户运行程序;终止。

6.3 Hello的fork进程创建过程

在终端里输入./hello 1180500705 ljh之后,shell接收到用户输入的命令,之后开始进行解析。由于“./hello”不是内置shell命令,shell会转而将其作为路径访问,即运行当前文件夹下的hello程序。当命令的第一个参数解析成功后,shell会创建一个子进程,并在子进程中执行程序。

6.4 Hello的execve过程

execve函数在当前进程的上下文中加载并运行一个新程序。当hello被fork之后,子进程通过execve函数在上下文中加载hello程序,覆盖掉当前进程的地址空间,调用启动代码设置栈,并将控制(命令行参数)传递给该程序的main函数。

6.5 Hello的进程执行

当程序开始执行之后,若当前进程未被抢占,则按照顺序运行,否则进行上下文切换:将当前进程上下文进行保存,恢复将要处理进程的上下文,并将控制传递给要处理的上下文。此时hello进程处于用户态。当执行到sleep函数时,经过atoi函数对数字参数的转换后,进程对sleep函数进行调用,并进入内核模式。内核对当前休眠请求进行处理,并将进程主动释放,进行上下文切换。等到计时结束时,定时器发出中断信号,内核接收之后再进行中断处理,继续运行hello进程,恢复上下文信息。

6.6 hello的异常与信号处理

下图为在运行过程中乱按(包括回车)的效果。在运行过程中进行普通的输入操作,是将输入的内容存入stdin,只有当执行到getchar函数时才会读取一个以“\n”结尾的字符串。之后的内容会被识别为在shell中输入的命令。

下图为输入Ctrl-Z的效果。此时向shell父进程发出了SIGSTP信号,接收到信号后信号处理函数输出提示信息,并将hello进程挂起。

下图为输入Ctrl-Z后运行ps命令的效果,验证了hello进程被挂起而没被回收的结论。

下图为输入Ctrl-Z后运行jobs命令的效果。

下图为输入Ctrl-Z后输入pstree命令的效果,将各个进程关系绘制成了树状图。

下图为输入Ctrl-Z后运行fg命令的效果,将被挂起的hello进程恢复。

下图为输入Ctrl-C的效果。此时向shell父进程发送了SIGINT信号。hello进程被终止并回收。利用ps命令验证了hello进程被终止并回收的结论。

6.7本章小结

本章着眼于生成的hello程序是如何加载到内存之中并被shell利用forkexecve执行、被键盘输入的指令中断与挂起或回收的,并且对抢占情况下的上下文切换作出了讨论。

第7章 hello的存储管理

7.1 hello的存储器地址空间

逻辑地址:hello源程序经编译之后,在汇编程序中的地址;或相对于当前段的偏移地址。
线性地址:hello程序的逻辑地址经段机制转换成的虚拟地址。
虚拟地址:CPU生成的用来访问hello程序的地址,在被送入内存前需要翻译。
物理地址:hello相关程序在物理存储器中具体的单元位置。

7.2 Intel逻辑地址到线性地址的变换-段式管理

段式管理直接将逻辑地址转化为物理地址进行访问。这种地址由段号与偏移地址组成。段选择符由三个字段组成,共16位:请求特权级,表指示标志和索引值。其中表指示标志指出段描述符的位置。段描述符8个字节。段首地址存放在段描述符中,而后者又存放在GDT或LDT中。

7.3 Hello的线性地址到物理地址的变换-页式管理

页式管理的分页机制完成线性地址向物理地址的转换,它对虚拟地址内存空间进行分页。这种转换过程是一个一一映射。

虚拟地址包含虚拟页号(VPN)和虚拟页面偏移(VPO)两部分。CPU上的内存管理单元(MMU)利用VPN选择相应的页表条目,再从中获得物理页号,并将它与VPO结合,就可以求得该虚拟地址对应的物理地址。

7.4 TLB与四级页表支持下的VA到PA的变换

TLB是翻译后备缓冲器,它保存着由单个PTE组成的块。翻译地址时需要现在其中查询是否命中。若命中,则可以直接取得对应的物理地址。

在地址转换时,需要现将VPN分为TLB标记和TLB索引,并检查TLB是否命中。若为命中,则将虚拟地址分为4个VPN和1个VPO。再利用这些索引确定一个物理页号,将之与VPO结合,即可得到物理地址。之后将其存入TLB中。

7.5 三级Cache支持下的物理内存访问

此处以L1 Cache为例,其他Cache同理。

L1 Cache为8路64组相联,块大小64B。易知需要6位CI与6位CO。又VA共52位,故CT为40位。

首先使用CI组索引,每组8路,分别匹配CT。若匹配成功,标志位为1,则命中,根据块偏移CO取得数据并将其返回;否则不命中,向下一级缓存中取出被请求的块,并进行放置。若映射到的组内由空闲块,则直接放置;否则产生冲突,采用最少使用策略对块进行清理替换。

7.6 hello进程fork时的内存映射

当shell进程调用fork函数之后,内核创建新的进程,并为其分配唯一的PID、创建虚拟内存,它创建了当前进程的mm_struct、区域结构和页表的原样副本,并将这两个进程的每个页面都标记为只读,将他们的每个区域结构都标记为私有的写时复制。

7.7 hello进程execve时的内存映射

execve函数被加载时,首先删除已经存在的用户区域,然后为hello程序的代码、数据、栈等创建新的私有的写时复制区域结构,然后再映射共享区域。最后设置程序计数器。

7.8 缺页故障与缺页中断处理

缺页即为DRAM缓存不命中。缺页是会触发一个缺页故障。缺页故障调用内核中的缺页异常处理程序,该程序会选择一个牺牲页。如果它已经被修改了,那么内核会将它复制回磁盘;否则正常写入。之后内核将从磁盘复制,写入内存并更新该页后返回,然后重新启动导致缺页的命令,将导致缺页的虚拟地址重新发送到地址翻译硬件,即可被正常处理。

7.9动态存储分配管理

在运行过程中如果需要额外虚拟内存,则可以使用动态内存分配器。它维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存片,要么是已分配的,要么是空闲的。已分配的块显式地保留为供应用程序使用。空闲块可用来分配。空闲块保持空闲,直到它显式地被应用所分配。一个已分配的块保持已分配状态,直到它被释放,这种释放要么是应用程序显式执行的,要么是内存分配器自身隐式执行的。

分配器有两种基本风格:显式分配器、隐式分配器。它们都要求应用显式地分配块。

显式分配器:要求应用显式地释放任何已分配的块;
隐式分配器:要求分配器检测一个已分配块何时不再使用,那么就释放这个块,自动释放未使用的已经分配的块的过程叫做垃圾收集。

C标准库提供的显示分配器是malloc程序包。

7.10本章小结

本章讨论了存储在存储器中程序的寻址细节,包括不同地址之间转换的不同方法;还讨论了程序执行时的内存管理细节,包括内存映射和内存分配等。

第8章 hello的IO管理

8.1 Linux的IO设备管理方法

设备的模型化:文件

文件类型:普通文件——包含任意数据;目录——包含一组链接的文件,其中每个链接都将一个文件名映射到一个文件,这个文件可能是另一个目录;套接字——用来与另一个进程进行跨网络通信的文件;命名通道;符号链接;字符;块设备等。

设备管理:unix io接口

统一方式:打开文件;改变当前的文件位置;读写文件;关闭文件。

8.2 简述Unix IO接口及其函数

open函数将filename转换为一个文件描述符,并且返回描述符数字。用来打开一个已存在的文件或者创建一个新文件。

close函数用来关闭一个打开的文件。

read函数从描述符为fd的当前文件位置复制最多n个字节到内存位置buf。用来执行输入。

write函数从内存buf位置复制至多n个字节到描述符fd的当前文件位置。用来执行输出。

8.3 printf的实现分析

(参考https://www.cnblogs.com/pianist/p/3315801.html

根据printf函数体及其调用函数可知,首先vsprintf生成显示信息,将所有的参数内容格式化之后存入buf,然后返回格式化数组的长度。之后利用write系统函数将buf中的i个元素写到终端的函数。然后到陷阱-系统调用int 0x80syscall

之后字符显示驱动子程序通过ASCII码在字模库获取点阵信息,并将其存储至vram中(存储每一个点的RGB颜色信息)。

最后显示芯片按照刷新频率逐行读取vram,并通过信号线向液晶显示器传输每一个点(RGB分量)。

8.4 getchar的实现分析

异步异常-键盘中断的处理:当用户使用键盘输入时,键盘会产生中断请求,传送相应按键的键盘扫描码。中断请求抢占当前进程,内核处理键盘中断处理子程序。系统接收到按键扫描码后将其相应地转成ASCII码,并保存到系统的键盘缓冲区。

getchar等调用read系统函数,通过系统调用读取按键ASCII码,直到接受到回车键才返回。

8.5本章小结

本章着重分析hello程序中涉及到的两个与IO有关的函数:printfgetchar,并对Unix的IO系统及其管理进行探究。

结论

在hello短暂的一生中,其实每一个过程都并不简单。

程序员首先将hello的程序编写出来,保存为hello.c文件;

接下来,预处理器将hello.c文件根据其中的宏定义进行扩充和替换,生成hello.i文件,用自动化的方法将小小的程序补充得更加庞大和复杂;

之后,编译器对扩充的hello.i文件进行汇编,并将汇编后的代码保存为hello.s文件;

接着,汇编器将hello.s进行汇编,生成机器语言文件(二进制文件)(可重定位目标程序)hello.o,此时的程序内容,我们的计算机已经能读懂了,只是它依然是残缺的,不能运行;

然后,链接器将hello.o文件与外部现有的共享库文件等链接,将原本残缺的位置填写完整,生成真正的可执行目标文件hello,此时的程序已经是可以被计算机加载并运行的完整文件了。

到了加载与执行的时候,用户需要通过shell(/bash)输入指定格式的命令,由shell调用fork创建子进程、调用execve进行替换,利用虚拟内存管理技术进行寻址和加载,利用异常控制流技术应对用户的“莽撞”。最后,当hello进程运行结束,shell的父进程对其进行回收,将它永远地删除。hello的一生结束了。

这样的一生看似是终结,但只要程序还在,它依然可以在计算机的内存中幻化出一个新的存在,一遍遍地“重生”。这样的终结也不完全是个悲剧。

通过对hello的一生进行的分析,我不由得惊叹计算机和计算机系统发明者的聪明才智,同时也庆幸如今的计算机硬件发展得如此发达,将如此繁多的复杂操作最后呈现得如此简单与迅速。这次探究历程也让我对全书的各项知识进行了复习与思索,让我对计算机系统有了更高、更具体的新认识。

参考文献

[1]  Randel E. Bryant等. 深入理解计算机系统(原书第3版)[M]. 北京:机械工业出版社,2016.

[2]  Acronyms relevant to Executable and Linkable Format (ELF).
https://www.cs.stevens.edu/~jschauma/631/elf.html

[3]  Stackoverflow. Why GCC compiled C program needs .eh_frame section?
https://stackoverflow.com/questions/26300819/why-gcc-compiled-c-program-needs-eh-frame-section

[4]  博客园. [转]printf函数实现的深入剖析.
https://www.cnblogs.com/pianist/p/3315801.html

为PC安装Chromium OS

文章所讨论内容并非“为PC安装CloudReady”。文章中出现的带星号(*)的小节可根据实际情况跳过。

请注意,Chromium OS系列安装时会抹掉整块硬盘重新分区,且不可与Windows在同一块硬盘中安装双系统。

Chromium OS中的Linux (Beta)功能依赖于PC硬件的虚拟化功能,不保证所有PC都可正常运行。由于Chromium OS系统原生只支持SS,不支持SSR与V2Ray,因此一旦无法开启Linux (Beta),就意味着可能无法登录Google帐号。不过,若有另外的Windows PC设备,可参考文章《通过Windows移动热点分享VPN连接》。

下载Chromium OS镜像

此处下载Chromium OS的稳定版本(Vanilla)并解压。

将Chromium OS镜像烧录至U盘

此处下载balenaEtcher。安装并打开balenaEtcher后,插入U盘。U盘容量以10GB以上为宜,且由于烧录时将会抹去U盘中的所有内容并重新分区,因此在烧录前需要将U盘中的资料备份。在balenaEtcher中的第一步选择解压后的Chromium OS镜像(.bin)文件,在第二步选择要烧录的U盘,点击“Flash!”按钮,等待烧录完成。

利用烧录了Chromium OS镜像的U盘为PC安装Chromium OS

本节内容可参考此页面(英语)。

将需要安装Chromium OS的PC关闭,开机时引导入U盘内的Chromium OS系统。配置网络后,在登录界面同时按下Ctrl+Alt+F2,进入终端,在“要登录用户”处输入chronos,登录后输入如下指令:

/usr/sbin/chromeos-install --dst /dev/sda

其中sda为PC中的第一块硬盘;若仅有一块硬盘,则该硬盘为sda。输入上述指令后,系统安装将自动进行。安装结束后,可重启计算机并拔去U盘。

*Chromefy

本节内容请参考此页面(英语)。

通过Windows移动热点分享VPN连接

文章所讨论内容建立在计算机操作系统为Windows 10 版本1903的基础上。

文章参考了花着露于方寸间的一个页面,但只讲述Windows上的操作方法,原因在于Android上的实现需要获取ROOT权限,要求较高,不适合一般用户;如有需求,请访问上述网页,并根据指导,通过Play商店安装VPN Hotspot

文章参考了长沙seo霜天博客的一个页面

文章中使用的方法需要借助第三方软件,不提供VPN服务如需正常使用,请自行联系服务提供商。该方法不仅限用于分享VPN连接,理论上移动热点开启的计算机设备上的其它网络状态也可以通过此方法分享。

安装SSTap

SSTap本为一款游戏加速器,如今其官网已因某些原因停止了该软件的开发、维护与下载。该软件的最新版本停留在Beta 1.1.0.1,但仍可在此处下载。

关闭杀毒软件,安装SSTap。在安装过程中,同意安装该软件的驱动程序。安装完成后,打开SSTap配置代理服务器。模式可选为“不代理中国IP”。

安装Connectify Hotspot

官网下载Connectify Hotspot并安装。

同时按下Windows+I,打开“设置”,依次点击“系统”、“投影到此电脑”,将右侧第一个下拉框选至“始终关闭”。

分享VPN连接

打开SSTap,点击“连接”。打开Connetify Hotspot,“创建…”项选择“Wi-Fi热点”,“要共享的Internet”项选择“TAP-Windows Adapter VX”(X为版本数字);可根据需求更改热点名称和密码。点击“启动热点”,即会创建对应名称的移动热点。

为小米8刷入Pixel Experience

文章所讨论内容建立在手机型号为小米8、刷入前的ROM为MIUI 10开发版、计算机操作系统为Windows 10的基础上。文章中出现的带星号(*)的小节可根据实际情况跳过。

在安装前,计算机端需要安装Android SDK。如果已安装了Android Studio,则Android SDK已经一并安装,安装目录默认为%USERPROFILE%\AppData\Local\Android\Sdk。另外,建议将%USERPROFILE%\AppData\Local\Android\Sdk\platform-tools添加至用户环境变量Path中,以便以后直接使用adb命令。

解锁Bootloader

此处申请解锁手机,需要先登录小米帐号获取资格后,再在此处获取解锁工具,进行解锁。使用解锁工具时也需要登录小米帐号进行资格检测。

手机在解锁之后,会自动重启。

*为小米手机刷入MIUI 10开发版

如果能够正常使用系统自带的卡刷方式刷入官网上提供的最新刷机包,则可以直接通过官方升级方式刷入MIUI 10开发版。若此方法不起作用(如出现错误提示,或提示“不允许刷入非最新版的开发版”),则可以通过线刷的方式刷入MIUI 10开发版。在此处获取小米手机线刷工具(MiFlash)。

由于官方已经取消了开发版线刷包的更新,并删除了已发布的开发版线刷包,故无法通过MIUI论坛或小米社区下载,但仍可通过此处(提取码:2ecq)或此处下载之前保存的官方版MIUI 10开发版线刷包。

在手机关机状态下同时按住电源键和音量减小键,将手机启动至Bootloader,将手机通过USB连接线连接计算机,打开MiFlash,依次点击“Driver”,“安装”。安装驱动后,选择下载的开发版线刷包,点击“加载设备”,选择设备后点击“刷机”即可。

如今直接使用小米手机线刷工具在稳定版系统上刷入开发版系统会导致无法开机;经测试,使用奇兔刷机线刷的开发版系统可以正常开机。另外,使用奇兔刷机也可刷入TWRP。

刷入TWRP

此处只介绍通过计算机端刷入TWRP的方法。

进入此页面,下载最新版本的TWRP镜像至计算机端。

可以使用奇兔刷机刷入该TWRP。

另外,也可以使用“命令提示符”刷入。

将手机通过USB连接线连接计算机,在手机上启用“开发者选项”,进入“开发者选项”,打开“通过USB调试”,并同意“一律允许此计算机进行调试”。

打开“命令提示符”(CMD),在为Android SDK添加过环境变量的情况下,输入如下指令:

adb reboot bootloader
fastboot flash recovery [twrp-xx.img路径]

刷入Pixel Experience

进入此页面,下载Pixel Experience ROM。将手机重启至Recovery模式,在TWRP中点击“清除”,将/data分区清除。回到TWRP的主界面, 将ROM拷贝至手机存储中, 点击“安装”,选择ROM所在路径,进行刷机。

获取Root权限

打开设置,进入授权管理,获取系统自带的Root权限。在开启Root权限前,系统会弹出确认窗口,并强制要求等待25秒(每5秒需要确认一次,并弹出下一个窗口)。

当获取Root权限后,手机会自动重启。

刷入Magisk

在手机上打开Magisk官网,下载安装Magisk Manager,在其中安装Magisk,方式选“直接安装”,此后Root权限将由Magisk掌管分配。

*进行原系统备份

请注意,该备份方法并不能将手机应用、设置、联系人等数据迁移至新系统中。

使用该方法备份前,请注意手机剩余存储空间是否充足。

在手机关机状态下同时按住电源键和音量增大键,或在计算机端的“命令提示符”中输入指令:

adb reboot recovery

使手机进入Recovery模式,就可以看到手机已成功刷入TWRP。

进入TWRP时需要输入锁屏密码,并且可以选择调整语言至简体中文。进入TWRP后选择“备份”,除默认分区外,还可以再另外勾选“System镜像”分区,进行备份。备份过程中会显示备份文件路径,在备份完成后将备份文件从其文件路径拷贝至计算机。

刷机后必须立刻做的事情

禁用首次开机指引(适用于Android Pie)

请注意,该方法并不适用于Android 10;Android 10用户请参考文章《通过Windows移动热点分享VPN连接》,设法在开机时连接至Google。另外,上述方法适用于各种Android版本,且更为推荐使用。

刷机完成后,先不要进入系统

在初次使用时,系统会进入开机指引。以往有时可以通过取出SIM卡的方式跳过网络相关的设置,但是现在这种方式并不稳定,有时会出现无法跳过,必须联网的现象。显然国内的网络情况无法满足。因此,为了避免出现这样的问题,减少不必要的麻烦,可以在开机前将开机指引禁用。

该方法参考了V2EX的一个页面

保持手机与计算机通过USB连接线连接,在手机TWRP界面内,点击“挂载”,勾选“/system”分区,点击“停用MTP模式”,再将其启用。

在计算机端打开“命令提示符”,输入指令:

adb pull system/build.prop [桌面路径]\build.prop

在桌面使用编辑器编辑拷贝得到的build.prop文件,在文件末尾添加:

ro.setupwizard.mode=DISABLED

保存后,在CMD中输入:

adb push [桌面路径]\build.prop system
adb shell
cd system/
chmod 0644 build.prop
exit

这样,开机指引就被禁用了。用户可以在初次开机时直接进入启动器界面,待时机合适时,可以通过通知栏或设置中的提示进行设置。

更换网络验证地址

禁用开机验证后,开启手机,连接无线网络之后,即使网络畅通,系统依然会显示网络不可用,原因是用于验证网络是否畅通的地址的服务器是Google的。

要解决该问题,则需要将网络验证地址更换,此处更换为MIUI的网络验证地址。

打开手机的开发者选项,开启“通过USB调试”,将手机通过USB连接线与计算机连接,在手机上点击“一律允许此计算机进行调试”。之后在计算机端的CMD中输入指令:

adb shell settings put global captive_portal_https_url https://connect.rom.miui.com/generate_204

JDK 11的环境变量配置

文章所讨论内容建立在使用Windows 10的基础上。

打开“编辑环境变量”。

  1. 新建系统变量,变量名填写JAVA_HOME,变量值填写JDK的安装路径。
  2. 编辑“Path”系统变量,点击“新建”,输入%JAVA_HOME%\bin,点击“确定”。

要验证环境变量设置妥当,请使用“命令提示符”(CMD)。打开CMD。

  1. 在CMD中输入java --version,回车,得到java版本信息。
  2. 在CMD中输入javac --version,回车,得到javac版本信息。