基础软件技术基础
技术点列举
- 领域常识
- git
- linux
- C
- 图吧垃圾佬
领域常识
-
指令集: 众所周知, 计算机的本质是由0和1组成的, 而这些0和1的排列规则就是指令集的本质, 比如以001101开头的32个0和1组成的数, 就是mips的一条指令格式, 许多条这种格式在一起, 就是指令集. 目前比较常听到的指令集包括arm64, amd64, x86_64, riscv, sw64, mips, loongarch等. 这些指令集具有相关专利, 指令集可控通常认为使用此指令集无需付费, 可以随意修改指令格式.
-
指令集架构: 上述许多指令形成了的指令集, 足够多的指令之间互相配合形成一种结构, 也就是指令集架构, 与指令集自主可控的区别是, 指令集架构自主可控仍然需要满足其对外提供的接口, 也就是ABI不能变. 就像人一只手拿一个苹果, 指令集架构可控可以让人在手肘处长出一个篮子, 装很多苹果, 但是一只手还是只能拿一个苹果.
-
ip内核: 指令集只是一团数字, 而用在我们的电脑上, 还需要由程序员将其写成代码, 程序员最终写成的代码, 就是ip核, 全称:intellectual property core. 而所谓的ip核架构自主可控就是使用这个ip核无需付费, 可以任意的去组装, 但是里面的东西不可以修改.
-
通用CPU: 一般指的是服务器用和桌面计算用CPU芯片, 我们常用的电脑芯片, 还有超星学习通服务器使用的芯片, 都属于通用CPU
-
超算: 即超级计算机, 可以有很多个CPU和GPU, 通常用于大型复杂项目的处理.
-
精简指令集: 指令的格式看着整齐的是精简指令集, 如riscv, alpha, arm, mips
-
复杂指令集: 指令集格式看着不那么整齐的是复杂指令集, 如x86
-
生态: 生存状态, x86的电脑到处都是, 软件数不胜数, 生态强大, sw64用于超算, 软件很少. 在计算机方面生态可以指软件的数量. 两大生态联盟: Windows+Intel, 简称Wintel体系, Android+Arm, 简称AA体系.
git
你可以不会linux, 但你必须要会git
-- 佚名
git分支操作的诱人之处
补丁之间有
关联, 现在A要合并补丁b和补丁c, 该怎么操作?
直白的:
css
git am b
git am c
不推荐的:
sql
git am b
patch -p1 < c
fix reject
git add .....
git commit ....
推荐的:
sql
git am b
git apply c --reject
fix reject
git add .....
git commit ....
git 流程:
挑着合入的:
csharp
git am b
git checkout HEAD~1 -b tmp
git switch tmp
git am c
git switch master
git cherry-pick tmp~0
fix reject
git add -u
git cherry-pick --continue
git 流程:
全部合入的:
csharp
git am b
git checkout HEAD~1 -b tmp
git switch tmp
git am c
git switch master
git merge tmp
fix reject
git add -u
git merge --continue
git 流程:
变基合入的:
csharp
git am b
git checkout HEAD~1 -b tmp
git switch tmp
git am c
git switch master
git rebase master tmp
fix reject
git add -u
git rebase --continue
git switch master
git merge tmp
git 流程:
上述操作只演示了一个目标分支上两个补丁之间的关系, 有些操作显得华而不实, 但是倘若分支数量和补丁数量都翻一倍呢?
假定有以下场景:
这时, 每次提供代码时, 如果只在一个分支操作, 那就需要不停执行git reset和git am
操作
如果这些需求是同一时间提出的, 那就需要复制多份文件夹, 每个文件夹起不同的名字, 然后再不同的文件夹中执行git reset和git am
操作
再假如我们可以提前预知这些操作, 大致操作如下:
css
cp -rf A A-X
cp -rf A A-Y
cp -rf A A-Z
cp -rf A A-M
cp -rf A A-N
cp -rf A A-MX
cp -rf A A-MN
cp -rf A A-YMZ
cp -rf A A-XN
cd A-X
git am x
cd ../A-Y
git am y
cd ../A-Z
git am z
cd ../A-M
git am m
cd ../A-N
git am n
cd ../A-MX
git am m
git am x
cd ../A-MN
git am m
git am n
cd ../A-YMZ
git am y
git am m
git am z
cd ../A-XN
git am x
git am n
假如使用分支操作呢?
css
git branch X
git am x
git branch Y
git am y
git branch Z
git am z
git branch M
git am m
git branch N
git am n
git checkout M -b MX
git cherry-pcik X~0
git checkout M -b MN
git cherry-pcik N~0
git checkout Y -b YMZ
git cherry-pcik M~0
git cherry-pcik Z~0
git checkout X -b XN
git cherry-pcik N~0
git流程如下:
此外, 再假如, YMZ补丁对应客户, 发现m补丁有问题, 需要不停调试, 同事Y和Z不用变化, 此时可以想一想, 复制文件夹和分支操作, 哪一种效率高, 可维护性强.
远程分支问题
git的一大亮点在于远程分支协同开发. 与其他开发者进行补丁交流是一大重点. 以下分享一些实用的Tips.
1. 下载补丁
-
Branch, 获取补丁后, 直接新建分支, 特性在于switch回原分支的时候, 该分支仍然存在, 后面需要用还能用.
-
Checkout, 获取补丁后, 处于分离的分支, 特性在于switch回原分支的时候, 该分支就不存在了, 如果只是看代码, 或者临时编译尝试功能时, 非常适合使用.
-
Cherry Pick, 获取补丁后, 基于当前补丁, 应用补丁, 不会切换分支, 相较于git am, 它是基于当前补丁, 只要不冲突就能直接打上, 而git am是基于补丁的父补丁, 补丁不冲突的时候可能也会多出一条merge信息(跟git服务相关).
-
Format Patch, 把补丁的内容作为标准输出, 并不应用补丁, 可以据此重定向为一个标准补丁再应用.
-
Pull, 会把补丁pull下来, 如果有冲突, 中间会出现merge信息, 如果没冲突, 会直接应用该补丁.
2. 分支拉取及推送
perl
git pull remote-url remoteBranch:localBranch
git push remote-url localBranch:remoteBranch
git push --delete remoteBranch
3. pr和mr
目前贡献代码有两种方式:
- fork源仓库, 自己开发完了以后, 提交pr请求源仓库合入
- 创建分支, 自己开发完以后, 提交到自己的分支上, 提交mr请求主分支合入
github上通常使用第一种, gitlab通常使用第二种.
gerrit属于第二种
4. 实战思路分析
main分支用于提交代码
out分支用于向不同客户提供软件
upstream分支用于时时更新, 便于main提交时rebase到最新
dev分支用于本地开发
linux
常见的shell操作要会:
-
硬件信息查看相关命令: lspci, lsusb, lsblk, fdisk, hwclock, sensors, busybox, dmidecode, lscpu, df, dh
-
系统信息查看相关命令: ntpdate, hwclock, date, uname, lsmod, modprobe, dmesg, df, dh, free, top, htop, ps, iostat
-
字符串处理相关命令: sed, awk, grep, cut, tr, tee, diff, uniq, td
-
自动化交互相关命令: expect-spawn, read, sshpass, 重定向
-
系统服务管理相关命令: dhclient, systemctl, su, journalctl, kill, jobs, service, ps, netstat, fuser, iostat
-
磁盘文件等相关命令: mkfs, mount, md5sum, fdisk, gpart, parted, file, mkswap, swapon, smartctl, fsck, xfs_repair
-
常用系统服务: ssh, dhcp, mount, ntp, ftp, http, nfs
-
常用接口测试命令: arecord, cvlc, wget, aplay, x11perf, iperf3, glmark2, fio, ip, ifconfig, ethtools
-
文本处理相关工具: nano, vi, vim, gedit, emacs, cat, diff
-
一些好用的循环处理工具及其他: watch, timeout, time, loop, seq, xargs
然后加以组合, 灵活运用
实战案例:
比如需要找到一个目录中不是文件夹的文件:
arduino
tree . | sed 's/\S* //g' | sed '$ d' | grep -v "/" | xargs -I N find . -name N | xargs -I N file N | grep -vw "directory$" | awk -F ':' '{print $1}'
比如想要列出所有的磁盘设备:
ini
lsblk -P | grep "TYPE=\"disk\"" | awk -F '"' '{print $2}'
灵活运用即可.
C语言
点击此处穿越回大学
学完C, 记得了解一下Makefile, 链接脚本等内容
debug
- 打印调试法
- gdb调试法
- 肉眼调试法
gdb
例如有如下C代码:
arduino
#include <stdio.h>
#include <stdlib.h>
static int si = 123;
int compare(int a, int b)
{
return (a >= b ? 1 : 0);
}
void info()
{
printf("a >= b!\n");
}
void main()
{
int i = 321;
if (!compare(si, i)) {
printf("a < b!\n");
}
}
先编译:
css
gcc -g a.c -o a
再使用gdb调试:
perl
$ gdb
GNU gdb (GDB) 13.2
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "loongarch64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file a
Reading symbols from a...
(gdb) list
4 static int si = 123;
5
6 int compare(int a, int b)
7 {
8 return (a >= b ? 1 : 0);
9 }
10
11 void info()
12 {
13 printf("a >= b!\n");
(gdb)
14 }
15
16 void main()
17 {
18 int i = 321;
19 if (!compare(si, i)) {
20 printf("a < b!\n");
21 }
22 }
(gdb) b 19
Breakpoint 1 at 0x810: file a.c, line 19.
(gdb) r
Starting program: /tmp/a/a
Breakpoint 1, main () at a.c:19
19 if (!compare(si, i)) {
(gdb) p !compare(si, i)
$1 = 1
(gdb) p si
$2 = 123
(gdb) p i
$3 = 321
(gdb) disassemble
Dump of assembler code for function main:
0x00005555555547f8 <+0>: addi.d $sp, $sp, -32(0xfe0)
0x00005555555547fc <+4>: st.d $ra, $sp, 24(0x18)
0x0000555555554800 <+8>: st.d $fp, $sp, 16(0x10)
0x0000555555554804 <+12>: addi.d $fp, $sp, 32(0x20)
0x0000555555554808 <+16>: addi.w $t0, $zero, 321(0x141)
0x000055555555480c <+20>: st.w $t0, $fp, -20(0xfec)
=> 0x0000555555554810 <+24>: pcalau12i $t0, 8(0x8)
0x0000555555554814 <+28>: ld.w $t0, $t0, 0
0x0000555555554818 <+32>: ldptr.w $t1, $fp, -20(0xffec)
0x000055555555481c <+36>: move $a1, $t1
0x0000555555554820 <+40>: move $a0, $t0
0x0000555555554824 <+44>: bl -172(0xfffff54) # 0x555555554778 <compare>
0x0000555555554828 <+48>: move $t0, $a0
0x000055555555482c <+52>: bnez $t0, 16(0x10) # 0x55555555483c <main+68>
0x0000555555554830 <+56>: pcalau12i $t0, 1(0x1)
0x0000555555554834 <+60>: addi.d $a0, $t0, -1952(0x860)
0x0000555555554838 <+64>: bl -616(0xffffd98) # 0x5555555545d0 <puts@plt>
0x000055555555483c <+68>: andi $zero, $zero, 0x0
0x0000555555554840 <+72>: ld.d $ra, $sp, 24(0x18)
0x0000555555554844 <+76>: ld.d $fp, $sp, 16(0x10)
0x0000555555554848 <+80>: addi.d $sp, $sp, 32(0x20)
0x000055555555484c <+84>: jirl $zero, $ra, 0
End of assembler dump.
(gdb) ni
0x0000555555554814 19 if (!compare(si, i)) {
(gdb) ni
0x0000555555554818 19 if (!compare(si, i)) {
(gdb) ni
0x000055555555481c 19 if (!compare(si, i)) {
(gdb) ni
0x0000555555554820 19 if (!compare(si, i)) {
(gdb) ni
0x0000555555554824 19 if (!compare(si, i)) {
(gdb) ni
0x0000555555554828 19 if (!compare(si, i)) {
(gdb) ni
0x000055555555482c 19 if (!compare(si, i)) {
(gdb) ni
20 printf("a < b!\n");
(gdb) bt
#0 main () at a.c:20
(gdb) si
0x0000555555554834 20 printf("a < b!\n");
(gdb) si
0x0000555555554838 20 printf("a < b!\n");
(gdb) si
0x00005555555545d0 in puts@plt ()
(gdb) si
0x00005555555545d4 in puts@plt ()
(gdb) c
Continuing.
a < b!
[Inferior 1 (process 277277) exited with code 07]
可以断点执行, 反汇编, 单步执行, 时时查看变量值, 非常方便.
gdbserver
在目标机器执行:
gdbserver :1235 a
在远程机器执行:
scss
(gdb) target remote 192.168.1.4:12345
通过此方法, 在嵌入式领域, 通过硬件调试器, 可以实现远程调试elf文件.
gcc工具链
除了上面的调试法, 还有一些信息需要指导, 当没有自动化的debug环境时, 可以通过自行反汇编, 对比代码执行流程, 比如objdump和nm工具:
objdump:
bash
$ objdump -D a | head -20
a: 文件格式 elf64-loongarch
Disassembly of section .interp:
0000000000000238 <.interp>:
238: 62696c2f blt $ra, $t3, -104084 # fffffffffffe6ba4 <_end+0xfffffffffffdeb44>
23c: 6c2f3436 bgeu $ra, $fp, 12084 # 3170 <__GNU_EH_FRAME_HDR+0x2908>
240: 696c2d64 bltu $a7, $a0, 93228 # 16e6c <_end+0xee0c>
244: 2d78756e .word 0x2d78756e
248: 6e6f6f6c bgeu $s4, $t0, -102548 # fffffffffffe71b4 <_end+0xfffffffffffdf154>
24c: 63726167 blt $a7, $a3, -36256 # ffffffffffff74ac <_end+0xfffffffffffef44c>
250: 706c2d68 .word 0x706c2d68
254: 2e643436 ldr.w $fp, $ra, -1779
258: 312e6f73 vstelm.w $vr19, $s4, -404, 0x3
...
Disassembly of section .note.gnu.build-id:
nm:
css
$ nm a | sort
0000000000000590 a _PROCEDURE_LINKAGE_TABLE_
00000000000005e0 T _start
0000000000000640 t deregister_tm_clones
00000000000006a0 t register_tm_clones
0000000000000700 t __do_global_dtors_aux
0000000000000760 t frame_dummy
0000000000000778 T compare
00000000000007c8 T info
00000000000007f8 T main
0000000000000850 R _IO_stdin_used
0000000000000868 r __GNU_EH_FRAME_HDR
0000000000007e40 a _DYNAMIC
0000000000008000 d si
0000000000008030 a _GLOBAL_OFFSET_TABLE_
0000000000008030 d __TMC_END__
0000000000008050 d __dso_handle
0000000000008058 B __bss_start
0000000000008058 b completed.0
0000000000008058 D _edata
0000000000008060 B _end
U abort@GLIBC_2.36
U __libc_start_main@GLIBC_2.36
U puts@GLIBC_2.36
w __cxa_finalize@GLIBC_2.36
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
相关工具及教程非常多, 不再演示.
图吧垃圾佬
主板, CPU, 电源, 风扇, 内存条, PCIE设备, sata, hdd, nvme, m.2, uart, vga, hdmi, flash, 网口, 蓝牙, usb口, usb扩展线, hda接口, ps/2接口, 等名称和图片应该能对的上.
显示器和主机能区分. 不会把电源线插vga口里就行