2022计算机系统大作业——程序人生-Hello’s P2P
计算机系统
大作业
题 目 程序人生-Hello’s P2P
专 业 计算机
学 号 120L021716
班 级 2003005
学 生 蔡泽栋
指 导 教 师 吴锐
计算机科学与技术学院
- 2021年5月
目录
第1章 概述
1.1 Hello简介
1.2 环境与工具
1.3 中间结果
1.4 本章小结
第2章 预处理
2.1 预处理的概念与作用
2.2在Ubuntu下预处理的命令
2.3 Hello的预处理结果解析
2.4 本章小结
第3章 编译
3.1 编译的概念与作用
3.2 在Ubuntu下编译的命令
3.3 Hello的编译结果解析
3.4 本章小结
第4章 汇编
4.1 汇编的概念与作用
4.2 在Ubuntu下汇编的命令
4.3 可重定位目标elf格式
4.4 Hello.o的结果解析
4.5 本章小结
第5章 链接
5.1 链接的概念与作用
5.2 在Ubuntu下链接的命令
5.3 可执行目标文件hello的格式
5.4 hello的虚拟地址空间
5.5 链接的重定位过程分析
5.6 hello的执行流程
5.7 Hello的动态链接分析
5.8 本章小结
第6章 hello进程管理
6.1 进程的概念与作用
6.2 简述壳Shell-bash的作用与处理流程
6.3 Hello的fork进程创建过程
6.4 Hello的execve过程
6.5 Hello的进程执行
6.6 hello的异常与信号处理
6.7本章小结
第7章 hello的存储管理
7.1 hello的存储器地址空间
7.2 Intel逻辑地址到线性地址的变换-段式管理
7.3 Hello的线性地址到物理地址的变换-页式管理
7.4 TLB与四级页表支持下的VA到PA的变换
7.5 三级Cache支持下的物理内存访问
7.6 hello进程fork时的内存映射
7.7 hello进程execve时的内存映射
7.8 缺页故障与缺页中断处理
7.9动态存储分配管理
7.10本章小结
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
8.2 简述Unix IO接口及其函数
8.3 printf的实现分析
8.4 getchar的实现分析
8.5本章小结
结论
附件
参考文献
第1章 概述
1.1 Hello简介
1.2 环境与工具
i7-X64 CPU;2.30GHz;2G RAM;256GHD Disk
Windows 10 64 位 VitualBox 15.1.0 Ubuntu 1 8 .04 LTS
Visual Studio 2022 64位;CodeBlocks 64位;vi/vim/gedit+gcc
1.3 中间结果
文件名称 |
说明 |
hello.c |
hello源文件 |
hello.i |
预处理后文件 |
hello.s |
编译得到的汇编文件 |
hello.o |
汇编后的可重定位目标文件 |
hello |
链接后可执行文件 |
hello.elf |
hello的elf文件 |
第2章 预处理
2.1 预处理的概念与作用
删除宏定义“#define”展开并解析所定义的宏,处理所有条件预编译指令。插入include后面的文件到“#include”处。删除所有的注释。最后将处理过后的新的文本保存在hello.i中。
2.2 在Ubuntu下预处理的命令
2.3 Hello的预处理结果解析
hello.i文件的内容增加到3000多行,预处理器对源文件中的宏进行了宏展开,对#define相应的符号进行了替换,同时也将系统头文件中的内容直接插入到了程序文本中。
2.4 本章小结
预处理是计算机对程序进行操作的第一个步骤,预处理器会对hello.c文件进行初步的解释,对头文件、宏定义和注释进行操作,将程序中涉及到的库中的代码补充到程序中,将注释这个对于执行没有用的部分删除。
第3章 编译
3.1 编译的概念与作用
概念:编译器将文本文件hello.i翻译成hello.s,它包含一个汇编语言程序。它是以高级程序设计语言书写的源程序作为输入,以汇编语言或者机器语言表示的目标程序作为输出。
作用:进行词法分析、语法分析和目标代码的生成,检查无误后生成汇编语言。
3.2 在Ubuntu下编译的命令
3.3 Hello的编译结果解析
第一个字符串“用法: Hello 学号 姓名 秒数!\n”存放在只读数据段.rodata中,被编码成utf-8格式,其中一个汉字占三个字节。
第二个字符串"Hello %s %s\n",输出传入的格式化参数,存放在只读数据段.rodata中。
用户传递给main函数的参数argc被放到了堆栈。19行将栈地址保存在%rbp中,第22行%edi保存函数传入的第一个参数即argc,存放在-20(%rbp)的位置。
argv每个元素char*大小为8字节,指针指向已分配好存放字符指针的连续空间,起始地址为argv。第23行%rsi保存函数传入的第二个参数即argv数组的首地址,存放在-32(%rbp)的位置。
访问数组元素argv[1],argv[2]和argv[3]时,按照起始地址argv大小8位计算数据地址取数据。
main函数内声明的局部变量i编译的时会放在堆栈中,即栈上-4(%rbp)的位置。
if语句判断argc!=4,设置条件码,为之后je跳转做准备。
for循环的条件判断i<8,比较i是否小于等于7,被编译为cmpl $7,-4(%rbp)。
控制转移在本程序中包括if条件分支引起的跳转以及for循环分支引起的跳转。通过关系操作cmpl进行比较设置条件码,之后根据条件码进行跳转。
传递数据:外部调用过程向main函数传递参数argc和argv,分别使用%edi和%rsi存储,将%eax设置0返回。
控制传递:第一次printf有一个字符串参数, call puts@PLT,第二次printf使用call printf@PLT。
3.4 本章小结
第4章 汇编
4.1 汇编的概念与作用
汇编指的是汇编器将hello.s翻译成机器语言指令,把这些指令打包成可重定位目标文件,并将结果保存在目标文件hello.o中。
hello.o是一个二进制文件,包含hello程序执行的机器指令。汇编的作用是将汇编语言翻译成机器可以直接读取分析的机器指令。
4.2 在Ubuntu下汇编的命令
4.3 可重定位目标elf格式
节名称 |
包含内容 |
.text |
已编译程序的机器代码 |
.rela.text |
一个.text节中位置的列表,链接器链接其他文件时,需修改这些内容 |
.data |
已初始化的全局和静态C变量 |
.bss |
未初始化的全局和静态C变量和所有被初始化为0的全局或静态变量 |
.rodata |
只读数据段 |
.comment |
包含版本控制信息 |
.symtab |
符号表,存放程序中定义和引用的函数和全局变量信息 |
符号表用来存放程序中定义和引用的函数和全局变量的信息,重定位需要引用的符号在其中声明。
描述了需要进行重定位的各种信息,包括需要进行重定位符号的位置、重定位的方式、名字。在hello.o中,对printf,exit等函数的未定义的引用替换为该进程的虚拟地址空间中机器代码所在的地址。
4.4 Hello.o的结果解析
objdump -d -r hello.o分析hello.o的反汇编。
机器语言是二进制机器指令的集合,而机器指令由操作码和操作数构成。
机器语言与汇编语言的映射关系:每一条汇编语言操作码都可以用机器二进制数据来表示,所有的汇编语言和二进制机器语言是一一映射关系。
反汇编代码跳转指令的操作数使用的不是段名称如.L3,段名称只是在汇编语言中便于编写的助记符。而在机器语言反汇编程序中,分支转移命令是直接跳转入目的地址。
4.5 本章小结
第5章 链接
5.1 链接的概念与作用
链接是将各种代码和数据片段收集并组合成一个单一文件的过程,这个文件可被加载到内存并执行。
作用:通过链接可以实现将头文件中引用的函数并入到程序中,解析未定义的符号引用,将目标文件中的占位符替换为符号的地址。完成程序中各目标文件的地址空间的组织。
5.2 在Ubuntu下链接的命令
5.3 可执行目标文件hello的格式
读取hello的ELF, 可以看到保存了可执行文件hello中的各个节的信息。如图5-2所示。hello文件中的节的数目比hello.o中多了很多,说明在链接过后有新文件添加进来。
hello的ELF头和hello.o的ELF头大体一致,但是类型从REL (可重定位文件)变为了EXEC (可执行文件),增加程序头起点,节头和字符串表索引节头的数量变多。
5.4 hello的虚拟地址空间
使用edb加载hello,查看本进程的虚拟地址空间各段信息。
可以看出.interp段在虚拟地址0x4002e0处,.dynstr段在0x400398处,.init段在0x401000处等。
同时在Data Dump中查看hello的虚拟地址空间开始处为0x401000。
5.5 链接的重定位过程分析
objdump -d -r hello得到hello的反汇编文件:
(2)重定位节中的符号引用这一步中,连接器修改代码节和数据节中对每个符号的引用,使他们指向正确的运行时地址。执行这一步,链接器依赖于可重定位目标模块中称为的重定位条目的数据结构。
(3)重定位条目当编译器遇到对最终位置未知的目标引用时,它就会生成一个重定位条目。代码的重定位条目放在.rela.txt
refptr = s + r.offset;/*ptr to reference to be relocated*/
if(r.type == R_X86_64_PC32){//PC相对寻址的引用
refaddr = ADDR(s) + r.offset;/*ref's run-time address*/
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr);
/*Relocate an absolute reference*/
if( r.type == R_X86_64_32){//使用32位绝对地址
*refptr = (unsigned)(ADDR(r.symbol) + r.addend);
*refptr = (unsigned) (ADDR(r.symbol) + r.addend - reffaddr)
5.6 hello的执行流程
使用edb执行hello,说明从加载hello到_start,到call main,以及程序终止的所有过程。
程序名称 |
程序地址 |
ld-2.27.so!_dl_start |
0x7ffff7a03b00 |
ld-2.27.so!_dl_init |
0x7ffff7de37d0 |
libc-2.27.so!__libc_start_main |
0x7ffffc827ab0 |
-libc-2.27.so!__cxa_atexit |
0x7ffffc849430 |
libc-2.27.so!_setjmp |
0x7ffffc844c10 |
libc-2.27.so!exit |
0x7ffffc849128 |
5.7 Hello的动态链接分析
动态链接就是要将程序拆成几个独立的部分,在运行的时候将它们连接起来,与静态链接把所有模块都链接成一个可执行文件不同。
PLT是一个数组,其中每个条目是16字节代码。每个库函数都有自己的PLT条目,PLT[0]是一个特殊的条目,跳转到动态链接器中。从PLT[2]开始的条目调用用户代码调用的函数。
GOT也是一个数组,每个条目是8字节的地址,和PLT联合使用时,GOT[2]是动态链接在ld-linux.so模块的入口点,其余条目对应于被调用的函数,在运行时被解析。每个条目都有匹配的PLT条目。
5.8 本章小结
本章介绍了链接的概念和作用,详细介绍了hello.o如何成为可执行的目标文件,详细介绍了hello.o的ELF形式和各节的意义,分析了hello的虚拟地址空间、重置进程、运行进程和动态链接过程。
第6章 hello进程管理
6.1 进程的概念与作用
一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器;一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用内存系统。
6.2 简述壳Shell-bash的作用与处理流程
Shell是一个用C语言编写的程序,他是用户使用Linux的桥梁。Shell是一个交互型应用级程序,代表用户运行其它程序。
6.3 Hello的fork进程创建过程
fork被调用一次,返回两次。在父进程中fork返回子进程的pid,在子进程中fork返回0。父进程与子进程是并发运行的独立进程。
6.4 Hello的execve过程
1.删除已存在的用户区域。删除当前进程虚拟地址的用户部分存在的区域结构。
3. 映射共享区域。如果hello程序与共享对象相连,例如标准C库libc.so所有对象都将被动态地连接到该程序中,并反映到用户的虚拟中。地址空间的共享区域。
4.设置程序计数器。exceve最后做的就是将当前进程上下文中的程序柜台设置为指向代码区域的入口。调用此进程从这个入口开始实行。Linux可根据需要更换代码和数据页面。
6.5 Hello的进程执行
结合进程上下文信息、进程时间片,阐述进程调度的过程,用户态与核心态转换等等。
上下文是内核重新启动一个被抢占的进程所需要的状态,它由通用寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构等对象的值构成。
当内核选择一个新的进程运行时,则内核调度了这个进程。在内核调度了一个新的进程运行后,它就抢占当前进程,并使用一种称为上下文切换的机制来将控制转移到新的进程:
6.6 hello的异常与信号处理
中断:信号SIGTSTP,默认行为是 停止直到下一个SIGCONT
程序正常运行的结果如下图所示,程序执行完后进程被回收,再按回车键退出程序。
运行时乱按时的结果如下图所示,乱按的输入并不会影响进程的执行,当按到回车键时,getchar会读入回车符,并且后面的字符串会当作shell的命令行输入。
运行时按Ctrl+Z后结果如下图所示。按下Ctrl+Z后父进程收到SIGTSTP信号,将hello进程挂起,ps命令列出当前系统中的进程。运行jobs命令列出当前shell环境中已启动的任务状态。
运行时按Ctrl+C后结果如下图所示。父进程收到SIGINT信号,终止hello进程,并且回收hello进程。
6.7本章小结
本章介绍了进程的概念及作用,shell的作用及其处理流程,并分析了hello的fork进程创建过程、execve过程和进程执行过程,最后根据不同情况分析了hello运行过程中的异常和信号处理。
第7章 hello的存储管理
7.1 hello的存储器地址空间
逻辑地址是指由程序产生的与段相关的偏移地址部分。逻辑地址由一个段(segment)和偏移量(offset)组成,偏移量指明了从段开始的地方到实际地址之间的距离。
线性地址是逻辑地址到物理地址变换之间的中间层。在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。
虚拟地址是程序保护模式下,程序访问存储器所使用的逻辑地址称为虚拟地址,与实地址模式下的分段地址类似,虚拟地址也可以写为“段:偏移量”的形式,这里的段是指段选择器。就是hello里面的虚拟内存地址。
CPU通过地址总线的寻址,找到真实的物理内存对应地址。在前端总线上传输的内存地址都是物理内存地址。
7.2 Intel逻辑地址到线性地址的变换-段式管理
1. 给定一个完整的逻辑地址[段选择符:段内偏移地址],首先根据T1的值,确定当前要转换是GDT中的段,还是LDT中的段,再依据对应寄存器,得到其地址和大小。
2. 根据段选择符中前13位,在数组中查找到相应的段描述符,获得基地址。
7.3 Hello的线性地址到物理地址的变换-页式管理
线性地址(即虚拟地址VA)到物理地址(PA)之间的转换通过分页机制完成。而分页机制是对虚拟地址内存空间进行分页。
7.4 TLB与四级页表支持下的VA到PA的变换
Intel i7的地址翻译用到了TLB与四级页表的技术,其中虚拟地址48位,物理地址52位,页表大小为4KB,页表为4级。
CPU产生虚拟地址VA,传给MMU,MMU使用前36位作为VPN,在TLB中搜索,如果命中,就得到其中的40位物理页号PPN,与12位VPO合并成52位的物理地址PA。
7.5 三级Cache支持下的物理内存访问
L1 Cache是8路64组相连高速缓存。块大小64B。因为有64组,所以需要6 位CI进行组寻址,共有8路,块大小为64B,所以需要6位CO表示数据偏移位置,VA共52位,所以CT共40位。
在上一步中已经获得了物理地址VA,使用CI进行组索引,每组8路,对8路的块分别匹配CT(前40位)。如果匹配成功且块的valid标志位为1,则命中,根据数据偏移量CO(后六位)取出数据返回。
7.6 hello进程fork时的内存映射
7.7 hello进程execve时的内存映射
hello程序与共享对象libc.so链接,libc.so是动态链接到这个程序中的,然后再映射到用户虚拟地址空间中的共享区域内。
设置当前进程上下文的程序计数器,使之指向代码区域的入口点。下一次调度这个进程时,将从这个入口点开始执行。
7.8 缺页故障与缺页中断处理
当指令引用一个相应的虚拟地址,而与改地址相应的物理页面不在内存中,就会引发缺页故障。
假设MMU在试图翻译某个地址时,触发了一个缺页。这个异常导致控制转移到内核的缺页处理程序,处理程序随后就执行下面的步骤:
1.检查虚拟地址是否合法。该步骤主要检查虚拟地址是否是指向某个区域结构定义的区域内,即是否在访问范围内。如果不在区域内,访问的页是不存在的,则会报错,并终止进程。
2.要进行的内存访问是否合法。主要判断是否满足读、写或者执行这个区域内页面的权限。例如,如果是因为试图对一个只读页面进行写操作而引起的缺页中断,那么缺页处理程序会触发一个保护异常,并终止这个程序。
这样,当却也处理程序返回时,CPU会重启引起缺页的指令,而这时就没有了缺页的情况。
7.9动态存储分配管理
动态内存分配器维护着一个进程的虚拟内存区域,称为堆。分配器将堆视为一组不同大小的块的集合来维护。每个块就是一个连续的虚拟内存空间,其要么是已分配的,要么是空闲的。动态内存分配主要有两种基本方法与策略:
隐式空闲链表通常带有一个头部和脚部标签,内容相同,记录块的大小和是否分配等信息。一般来说每个块都是由头部和脚部、有效载荷、可能的额外填充组成,对于某些优化的链表,已分配的块可以没有脚部。
在隐式空闲链表中,所有的块都是通过头部和脚部中的大小字段连接着的。因此分配器可以依次遍历整个堆。其中,一个设置了已分配的位而大小为零的终止头部将作为特殊标记的结束块。
显式空闲链表是将空闲块组织为某种形式的显式数据结构。堆被组织成一个双向链表,在每个空闲块中,都包含一个前驱与一个后继指针。
7.10本章小结
第8章 hello的IO管理
8.1 Linux的IO设备管理方法
8.2 简述Unix IO接口及其函数
关闭文件:进程通过调用close 函数关闭一个打开的文件。int close(int fd)。
应用程序是通过分别调用read 和write 函数来执行输入和输出的。
ssize_t write(int fd, const void *buf, size_t n),write函数从内存位置buf复制至多n个字节到描述符为fd的当前文件位置。
int stat(const char *filename, struct stat *buf);
int fstat(int fd, struct stat *buf);
8.3 printf的实现分析
printf函数功能:接受字符串指针数组fmt,然后将匹配到的参数按照fmt格式输出,返回字符串的长度。printf内部调用了两个外部函数:vsprintf和write。
vsprintf的作用是格式化接受确定输出格式的字符串fnt。用格式字符串对个数变化的参数进行格式化,产生格式化输出,并返回要打印的字符串的长度。
write(buf,i)执行写操作,把buf中的i个元素的值输出。write函数中,先给寄存器传递参数,然后执行系统调用syscall。
8.4 getchar的实现分析
异步异常-键盘中断的处理:键盘中断处理子程序。接受按键扫描码转成ascii码,保存到系统的键盘缓冲区。getchar等调用read系统函数,通过系统调用读取按键ascii码,直到接受到回车键才返回。
8.5本章小结
本章简述了Linux的I/O设备管理机制,Unix I/O接口及函数,并简要分析了printf函数和getchar函数的实现。
结论
2.预处理:预处理器将hello.c调用的所有外部的库展开合并到一个hello.i文件中。
3.编译:编译器(ccl)将解释完预处理指令的hello.i文件进行编译,得到汇编程序(文本)hello.s文件。
4.汇编:汇编器(as)将汇编程序hello.s中的汇编语言转换成机器语言,生成重定位信息,将这些代码和信息生成为一个可重定位目标程序hello.o。
5.链接:链接器(ld)将hello.o与可重定位目标文件和动态链接库链接成为可执行目标程序hello。
6.创建进程:在shell命令行输入./hello,shell解释命令并调用fork函数创建一个子进程。
7.加载程序:加载器调用execve函数,在当前进程(新创建的子进程)的上下文中运行hello程序。
8.内存管理:运行hello时,内存管理单元MMU、翻译后备缓冲器TLB、多级页表机制、三级cache等计算机中的各个组成部件共同运转和配合,完成对内存地址的解析、请求、返回、访问。
9.异常处理:如果运行中键入Ctrl + C或Ctrl + Z,则调用shell的信号处理函数分别停止、挂起。如果产生缺页异常,则缺页处理程序选择合适的牺牲页替换,并重新加载相应命令。
10.结束:当hello运行完毕,向父进程shell发送SIGCHLD信号,提示进程已终止,然后父进程回收hello,内核删除为hello进程创建的所有数据结构。
附件
文件名称 |
文件说明 |
hello.c |
hello源文件 |
hello.i |
预处理后文本文件 |
hello.s |
编译得到的汇编文件 |
hello.o |
汇编后的可重定位目标文件 |
hello |
链接后可执行文件 |
hello.objdump |
hello可执行文件反汇编代码 |
hello.elf |
hello的elf文件 |
参考文献
Open Source Guides - Linux Foundation
[2] UTF-8编码规则 UTF-8编码规则(转)_vincent_smm的博客-CSDN博客
[3] ELF文件格式解析ELF文件格式解析_mergerly的博客-CSDN博客_elf文件格式.
[4] 内存地址转换与分段内存地址转换与分段_drshenlei的博客-CSDN博客
[5] Linux下逻辑地址、线性地址、物理地址详细总结Linux下逻辑地址、线性地址、物理地址详细总结_FreeeLinux的博客-CSDN博客_linux 物理地址 线性地址 逻辑地址
[6] printf 函数实现的深入剖析 [转]printf 函数实现的深入剖析 - Pianistx - 博客园
[7] Linux的jobs命令 Linux的jobs命令_SnailTyan的博客-CSDN博客_jobs指令
[8] 兰德尔E.布莱恩特,大卫R.奥哈拉伦. 深入理解计算机系统. 北京:机械工业出版社,2016年11月第1版.
2022计算机系统大作业——程序人生-Hello’s P2P相关推荐
- 【2022】哈工大计算机系统大作业——程序人生Hello’s P2P
2022哈工大计算机系统大作业--程序人生Hello's P2P 摘要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概 ...
- HIT 深入理解计算机系统 大作业 程序人生-Hello’s P2P
HIT 深入理解计算机系统 大作业 程序人生-Hello's P2P 本论文旨在研究 hello 在 linux 系统下的整个生命周期.结合 CSAPP 课本, 通过 gcc 等工具进行实验,从而将课 ...
- 2022春 计算机系统大作业 程序人生-Hello’s P2P
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算学部 学 号 班 级 学 生 指 导 教 师 计算机科学与技术学院 2022年5月 摘 要 为深入理解计算机系统,本文以hel ...
- 哈工大2022春计算机系统大作业:程序人生-Hello‘s P2P
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机类 学 号 120L021305 班 级 2003002 学 生 李一凡 指 导 教 ...
- 【哈工大2022计算机系统大作业“程序人生”】
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机 学 号 120L021504 班 级 2003012 学 生 乔江洋 指 导 教 师 郑贵滨 计算机科学与技术学院 202 ...
- 哈工大2022计算机系统大作业---程序人生
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机类 学 号 120L021923 班 级 2003006 学 生 甄自镜 指 导 ...
- 哈工大计算机系统大作业 程序人生-Hello’s P2P 2022
2022哈工大计算机系统大作业 目录 摘 要 第1章 概述 1.1 Hello简介 1.2 环境与工具 1.3 中间结果 1.4 本章小结 第2章 预处理 2.1 预处理的概念与作用 2.2在Ubun ...
- 哈工大 计算机系统大作业 程序人生-Hello’s P2P From Program to Process
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算学部 学 号 120L020512 班 级 2003004 学 生 黄鹏程 指 导 ...
- 哈工大计算机系统大作业-程序人生-Hello’s P2P
计算机系统 大作业 题 目 程序人生-Hello's P2P 专 业 计算机科学与技术 学 号 2021110802 班 级 21w0312 学 生 黄键树 ...
最新文章
- linux服务器读写硬盘io,查看linux服务器硬盘IO读写负载
- 【转】Linux 之 /etc/profile、~/.bash_profile 等几个文件的执行过程
- 动态库在线更新导致coredump的问题
- 软件设计师09-面向对象-用例图
- django项目开发1:搭建虚拟环境
- 高文院士:从“乡村教师”到人工智能掌舵者的40年科研路
- putty远程登录linux有啥用,putty 自动远程登录linux
- JeeWx 微信开发公开课(Jeewx-API 专题),今晚8点不见不散
- 旅游信息管理后台(SSM后台管理系统)
- MSNP18协议分析(一)--- MSN协议介绍
- Power Apps相关介绍
- 题解 P1757 【通天之分组背包】
- linux -m32,32位gcc和64位gcc与-m32选项有什么区别?
- FTT价值评估报告 | TokenInsight
- Xilinx FPGA clk_wiz IP使用
- 数据科学系列:plotly可视化入门介绍
- 小熊派开发板移植RT-FOTA
- 体温单怎么画 体温表_准备好承受体温-很多
- 安氏图书报刊发行管理软件——图书人自己亲手开发的软件
- python手写画直方图
热门文章
- shiro中使用自定义filter后,anon不生效解决方案
- 概率论考点之指数分布,泊松分布及积分(一维随机变量内容)
- 谷歌ai人工智能叫什么_Google DeepMind在全球使用AI的10种方式
- mysql中解决“SELECT command denied to user ‘nature‘@‘192.168.1.49‘ for table ‘user_variables_by_thread‘“
- 计算机专业有哪些有含金量的证书,大学最有含金量的6大类证书!你拥有哪几个?...
- 自己动手写CPU之第九阶段(2)——加载存储指令说明2(lwl、lwr)
- linux tahoma字体,linux - 更好的Ubuntu字体 - Ubuntu问答
- Modulo Summation atcoder abc103
- Mixly第三方用户库开发Arduino UNO使用EMW3080连接阿里云
- 如何使用Dart的Stream(一)