基础软件技术基础

基础软件技术基础

技术点列举

  1. 领域常识
  2. git
  3. linux
  4. C
  5. 图吧垃圾佬

领域常识

  1. 指令集: 众所周知, 计算机的本质是由0和1组成的, 而这些0和1的排列规则就是指令集的本质, 比如以001101开头的32个0和1组成的数, 就是mips的一条指令格式, 许多条这种格式在一起, 就是指令集. 目前比较常听到的指令集包括arm64, amd64, x86_64, riscv, sw64, mips, loongarch等. 这些指令集具有相关专利, 指令集可控通常认为使用此指令集无需付费, 可以随意修改指令格式.

  2. 指令集架构: 上述许多指令形成了的指令集, 足够多的指令之间互相配合形成一种结构, 也就是指令集架构, 与指令集自主可控的区别是, 指令集架构自主可控仍然需要满足其对外提供的接口, 也就是ABI不能变. 就像人一只手拿一个苹果, 指令集架构可控可以让人在手肘处长出一个篮子, 装很多苹果, 但是一只手还是只能拿一个苹果.

  3. ip内核: 指令集只是一团数字, 而用在我们的电脑上, 还需要由程序员将其写成代码, 程序员最终写成的代码, 就是ip核, 全称:intellectual property core. 而所谓的ip核架构自主可控就是使用这个ip核无需付费, 可以任意的去组装, 但是里面的东西不可以修改.

  4. 通用CPU: 一般指的是服务器用和桌面计算用CPU芯片, 我们常用的电脑芯片, 还有超星学习通服务器使用的芯片, 都属于通用CPU

  5. 超算: 即超级计算机, 可以有很多个CPU和GPU, 通常用于大型复杂项目的处理.

  6. 精简指令集: 指令的格式看着整齐的是精简指令集, 如riscv, alpha, arm, mips

  7. 复杂指令集: 指令集格式看着不那么整齐的是复杂指令集, 如x86

  8. 生态: 生存状态, x86的电脑到处都是, 软件数不胜数, 生态强大, sw64用于超算, 软件很少. 在计算机方面生态可以指软件的数量. 两大生态联盟: Windows+Intel, 简称Wintel体系, Android+Arm, 简称AA体系.

git

你可以不会linux, 但你必须要会git -- 佚名

git分支操作的诱人之处

graph LR A -->|提供一份代码X| B B -->|增加补丁b| A A -->|提供相同代码X| C C -->|增加补丁c| A

补丁之间关联, 现在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 流程:

--- title: 常规操作 --- gitGraph commit id: "a" commit id: "b" commit id: "c"

挑着合入的:

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 流程:

--- title: 补丁提取 --- gitGraph commit id:"a" branch tmp commit id:"c" checkout main commit id:"b" cherry-pick id:"c"

全部合入的:

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 流程:

--- title: 补丁合并 --- gitGraph commit id:"a" branch tmp commit id:"c" checkout main commit id:"b" merge tmp id:"mergeC"

变基合入的:

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 流程:

--- title: 补丁合并 --- gitGraph commit id:"a" branch tmp commit id:"c" checkout main commit id:"b" checkout tmp merge main id:"rebase" checkout main merge tmp id:"MergeRebase"

上述操作只演示了一个目标分支上两个补丁之间的关系, 有些操作显得华而不实, 但是倘若分支数量和补丁数量都翻一倍呢?

假定有以下场景:

graph LR A -->|增加补丁x| X A -->|增加补丁y| Y A -->|增加补丁z| Z A -->|增加补丁m| M A -->|增加补丁n| N A -->|增加补丁m和补丁x| MX A -->|增加补丁m和补丁n| MN A -->|增加补丁y和补丁m和补丁z| YMZ A -->|增加补丁x和补丁n| XN

这时, 每次提供代码时, 如果只在一个分支操作, 那就需要不停执行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流程如下:

--- title: 基于分支提供代码 --- gitGraph commit id:"a" branch X branch Y branch Z branch M branch N checkout X commit id:"x" branch XN checkout Y commit id:"y" checkout Z commit id:"z" checkout M commit id:"m" branch MX branch MN branch YMZ checkout N commit id:"n" checkout MX merge X id:"mx" checkout MN merge N id:"mn" checkout YMZ merge Y id:"ym" merge Z id:"ymz" checkout XN merge N id:"xn"

此外, 再假如, 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

目前贡献代码有两种方式:

  1. fork源仓库, 自己开发完了以后, 提交pr请求源仓库合入
  2. 创建分支, 自己开发完以后, 提交到自己的分支上, 提交mr请求主分支合入

github上通常使用第一种, gitlab通常使用第二种.

gerrit属于第二种

4. 实战思路分析

--- title: 一份代码同时用于生产, 开发, 不同类型的测试 --- gitGraph commit id:"a" branch out1 branch out2 branch out3 branch upstream branch dev checkout out2 commit id:"y" checkout out3 commit id:"z" checkout upstream commit id:"fix bug" commit id:"add func" commit id:"optimze func" checkout dev commit id:"My func" checkout main merge upstream checkout out1 commit id:"x" checkout out1 cherry-pick id:"add func" cherry-pick id:"My func" checkout main cherry-pick id:"My func"

main分支用于提交代码

out分支用于向不同客户提供软件

upstream分支用于时时更新, 便于main提交时rebase到最新

dev分支用于本地开发

linux

常见的shell操作要会:

  1. 硬件信息查看相关命令: lspci, lsusb, lsblk, fdisk, hwclock, sensors, busybox, dmidecode, lscpu, df, dh

  2. 系统信息查看相关命令: ntpdate, hwclock, date, uname, lsmod, modprobe, dmesg, df, dh, free, top, htop, ps, iostat

  3. 字符串处理相关命令: sed, awk, grep, cut, tr, tee, diff, uniq, td

  4. 自动化交互相关命令: expect-spawn, read, sshpass, 重定向

  5. 系统服务管理相关命令: dhclient, systemctl, su, journalctl, kill, jobs, service, ps, netstat, fuser, iostat

  6. 磁盘文件等相关命令: mkfs, mount, md5sum, fdisk, gpart, parted, file, mkswap, swapon, smartctl, fsck, xfs_repair

  7. 常用系统服务: ssh, dhcp, mount, ntp, ftp, http, nfs

  8. 常用接口测试命令: arecord, cvlc, wget, aplay, x11perf, iperf3, glmark2, fio, ip, ifconfig, ethtools

  9. 文本处理相关工具: nano, vi, vim, gedit, emacs, cat, diff

  10. 一些好用的循环处理工具及其他: 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

  1. 打印调试法
  2. gdb调试法
  3. 肉眼调试法

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口里就行

相关推荐
舞动CPU4 小时前
linux c/c++最高效的计时方法
linux·运维·服务器
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端
唔知小罗7 小时前
git config是做什么的?
git
keep__go8 小时前
Linux 批量配置互信
linux·运维·服务器·数据库·shell
矛取矛求8 小时前
Linux中给普通账户一次性提权
linux·运维·服务器
Fanstay9858 小时前
在Linux中使用Nginx和Docker进行项目部署
linux·nginx·docker
大熊程序猿8 小时前
ubuntu 安装kafka-eagle
linux·ubuntu·kafka
daizikui10 小时前
Linux文件目录命令
linux·运维·服务器
NikitaC10 小时前
ldconfig 和 LD_LIBRARY_PATH 区别
linux·c++