linux0.00 代码阅读笔记

2023-10-29

----------------------------------------
汇编语言的编写, 编译, 运行,调试:
author: hjjdebug
date:

----------------------------------------

参考代码地址:GitHub - hjjdebug/linux0.00: linux0.00 code, compiled under ubuntu14.04, gcc 4.8

ubuntu14 的环境这里用gdb(4.8.4)+bochs(2.4.6)来调试

原来曾经读懂了linux0.00代码, 后来翻阅, 发现又有生疏感,干脆写一篇笔记。记录一下。

汇编语言依赖于cpu, 这里以intel 系列(80x86)为研究对象.
1. 汇编语言的书写有它自己的格式,请参考相关书籍。
2. 编译,生成目标文件,可执行文件及列表文件。
     目标文件,可执行文件也可反编译成.s 文件
    objdump86 可以研究8086二进制代码
3. 运行与调试,跟踪程序的执行过程。调试能够观察寄存器,
    观察内存,也能够反编译代码。

bochs. 是intel x86虚拟机。虚拟机好处多,高度可配置,而且
    它不仅可以调试8086 16bits cpu
    而且还可以调试80386 32bits保护模式程序
    运行方式 bochs -f config.bxrc

实例: linux0.00 程序

1. 编写:代码已经书写好了。
2. 编译: 需要先了解Makefile 文件,了解它的编译过程, 还要满足
        自己的一些需求,例如生成列表,反汇编等
    看着列表完备的信息,及寥寥几行boot 8086 代码,不用调试也差不多都懂了。
    顺便说一句, 此时读取磁盘数据只能通过磁头,磁道,扇区调用int13中断读取。

3. 调试:
    bochs 调试由于没有调试初始化文件, 每次调试做重复性劳动太过浪费时间
    把设置断点以及其它设置(例如每条指令执行前显示寄存器等)放到一个键盘序列上。
    熟悉它的调试功能, h 有帮助信息, s 单步, n 宏单步, r寄存器,m内存等
    调试一定要顺手,熟悉功能,满足自己需要才能有效率。


基本技能: 验证简单汇编代码(80386保护模式)功能, 步骤!
由于bochs-dbg 没有小汇编功能, 测试还需要编写,编译,运行这个过程, 所以需要一个简单环境。
如果直接调试,也要很方便的中断,然后跟踪调试。
最后还是选用了带gdb 调试功能的bochs, 它与带dbg调试功能的bochs 相冲突,只能编译出一种功能, 还是带gdb调试接口的胜出.
----------------------------------------
linux0.00 关键代码分析:
----------------------------------------
1. 加载堆栈段及堆栈指针

addr    code                  ;comment
0007 lss init_stack,%esp      ;0FB225 600C0000
......

0A60 .fill 128,4,0            ; 000000... 128*4 个0
0c60 init_stack:                         
        .long init_stack     ; 600C0000, 定义堆栈地址
        .word 0x10            ; 1000
加载堆栈段寄存器和堆栈指针寄存器。直接寻址指令。
从init_stack 地址所指单元中,加载6字节内容到esp,ss寄存器
这里注意: init_stack 向下,是定义了堆栈位置,
init_stack 向上, 就是堆栈位置。

at&t 汇编:直接寻址是不加()的,寄存器间接寻址是加()的., 立即数加$修饰
    

----------------------------------------
2. 清空屏幕:
把0720数值向显示缓冲区存储单元中丢,就能擦除一个字符,
07是属性,20是空格的ascii
感觉还是很神奇!

显示缓冲区段描述符: .quad 0x00c0920b80000002
换一种写法:         .word 0x0002, 0x8000, 0x920b, 0x00c0

段限:0x0002 加上0x00C0 的最后一个nibble(共20bits) 为段限长2
粒度为页(4K)--C 的最高位, 故段限为8K.
基址: 0x8000 加上0x920b的0b, 加上0x00c0 的00 构成熟知的0xb8000地址
其它: 
C 的次高位, (d/b位),为1表示采用32位。为0是16位,后面的两位可认为固定为00
0x92:  9 的最高位是存在位, 次2位00 表示描述符特权级, 下一位为1表示为代码或数据,若为0是系统位, 2为段类型
----------------------------------------
3. iret 指令详解: (从优先级0 转入优先级3,并切换到用户栈)
    pushl $0x17
    pushl $usr_stk0
    pushfl
    pushl $0x0f
    pushl $task0
    iret
iret 无疑会执行0x0f:task0, 并使用堆栈0x17:usr_stk0, 初始flag 为堆栈中flag.

它确定了CS,PC,EFLAG, SS,及ESP

但是: 还想知道, 0x0f:task0 的线性地址是多少?
1. 因为是0x0f, bit0,bit1表示优先级为3,

bit2 TI 位为1,所以选择ldt表,此时ldtr 值为0x0028,
调试器中显示:ldtr:0x0028, dh=0x0000e200, dl=0x0c680040, valid=1

0x0028 是由 ltr %ax ,(ax=0x28)加载的.

后面对应的数值是gdt中0x28处的描述符,是如下定义的.
.word 0x0040, ldt0, 0xe200, 0x0    # LDT0 descr 0x28
ldt0 被编译器计算为0x0c68, 它从这里可以拿到ldt表的起始位置.这就是调试器中显示的信息

下边再说说ldt表的内容.
0x0f 屏蔽低3位为0x08, 为ldt表第2项
.quad 0x00c0fa00000003ff    # base = 0x00000
由于0x0f选择子指向地址的base为0,所以0x0f:task0 的线性地址就是task0。


同理: 堆栈的地址:
0x17 屏蔽低3为为0x10, 为ldt表第3项
.quad 0x00c0f200000003ff    # 0x17
base 也是0, 堆栈的线性地址就是usr_stk0.


iret 后,系统会进入用户模式task0, 并在这里运行一段时间,不断调用int 80 软中断(也叫自陷)
在屏幕上显示'A'字符。直到发生定时器中断。
----------------------------------------
4. int 80 中断:
esp: 0x00002214 8724
000f:00002009 (unk. ctxt): int $0x80                 ; cd80

esp: 0x000011ec 4588
[0x00000000000001de] 0008:000001de (unk. ctxt): pushl %ds                 ; 1e
这个跳跃是如何实现的?堆栈是如何切换的?
看80号中断门:
    movw $system_interrupt, %ax        ; eax 高16位是 0x0008,为段选择子,低16位是地址低16位
    movw $0xef00, %dx                         ;edx 高16为为0, 是地址高16位, 0xef00参考后述
    movl $0x80, %ecx                ; 中断号0x80
    lea idt(,%ecx,8), %esi
    movl %eax,(%esi)
    movl %edx,4(%esi)

低16为(system_interrupt)为偏移值,高16位为0 (edx 高16位)组合成32位偏移地址
0x0008 为选择子, 解释清了代码段段选择子为8,偏移为system_interrupt

0xef00表示最高位1表示存在位,此两位11,优先级为3,下一bit表示系统, f为中断门,再后面的00认为是保留位。

所以当int 80 发生时,会进入内核态,因为定义的选择子是8,RPL 是0  (内核态),TI 是0(选择gdt表).

同理,发生时钟中断也是如此,运行在内核态.选择的是gdt表.

堆栈及指针(0x10 : 0x11ec)从哪里获得? 

是从TSS0 任务段描述符中获取的,这里定义了
中断时使用了kernel stack: krn_stack  0x1200

运行级别发生改变,就要从这里拿堆栈地址了!

看一下堆栈中保留的内容:
x/10 esp
0x000011ec <bogus+       0>:    0x0000200b    0x0000000f    0x00000246    0x00002214
0x000011fc <bogus+      16>:    0x00000017    0xaaaaaaaa
0x17:2214 : 用户的堆栈指针
0x246    :    用户flag
0xf:200b:    被中断的用户pc指针
这样,一个iret 指令就可以恢复到原来位置了。

定时器中断到后,将会进行任务切换!
----------------------------------------
5. 定时器中断:
在定时器中断服务程序入口设置断点,断不下来,靠!
再下面一条语句,可以断下来. 好! 继续分析...
定时器中断,跟int 80h 中断是很相像的。
此时看, 代码段值为0x08, 堆栈段值为0x10 why?
这要问问8号中断门了.
8号定时器中断:
    movl $0x00080000, %eax    
    movw $timer_interrupt, %ax
    movw $0x8E00, %dx         # edx 高16位为0,是32位基地址的高16位
    movl $0x08, %ecx              # The PC default timer int.
    lea idt(,%ecx,8), %esi
    movl %eax,(%esi)
    movl %edx,4(%esi)
低16为(timer_interrupt)为偏移值,高16位为0 (edx 高16位)组合成32位偏移地址
0x0008 为选择子, 解释清了代码段值为8,偏移为timer_interrupt

堆栈及指针(0x10 : 0x11e4)从哪里获得?
首先,中断时使用了kernel stack: krn_stack  0x1200
原来是在TSS0 任务段描述符中定义过,  为恢复现场提供数据
tss0:    .long 0             /* back link */
    .long krn_stk0, 0x10        /* esp0, ss0 */
    .long 0, 0, 0, 0, 0        /* esp1, ss1, esp2, ss2, cr3 */
优先级1,2没有对应代码,所有初始化为0. 优先级3呢? 这就是本任务的ss 和 esp, 保存在tss0后面结构项了.

目前堆栈中都保存了什么东西了呢?
<bochs:152> x/10 esp
0x000011e4 <bogus+       0>:    0x00000041    0x00000017    0x00002010    0x0000000f
0x000011f4 <bogus+      16>:    0x00000246    0x00002214    0x00000017    0xaaaaaaaa

尾巴上0xaaaaaaaa 是一个标记(0x1200地址),以此分界,下为堆栈
0x17:0x2214 保存的是用户进程堆栈位置
0x246 为用户进程flag
0x0f:2010: 保存用户进程执行代码位置。
此时的eflag, 已经是0x46, 中断标志if 已经清除,不能再接受可屏蔽中断。
0x17: 中断代码刚刚保存的ds 寄存器
0x41: 中断代码刚刚保存的eax 寄存器
后两个值已经是用户行为了。
----------------------------------------
6. 任务切换: 长跳转指令
    ljmp $TSS1_SEL, $0
从中断程序中,长跳转到一个任务状态段选择子。
当然,要跳转到这个任务段中所保留的位置了.
: ljmp 0030:00000000        ; ea000000003000
tr 寄存器内容也随之改变为TSS1_SEL,从它的描述符中对应位置取到一大堆信息,恢复环境.
一个跳转, IF 被开启
[0x0000000000002218] 000f:00002218 (unk. ctxt): movl $0x00000017, %eax    ; b817000000
看代码:

TSS1_SEL    = 0X30

gdt 表中的对应项是一个任务状态段描述符。

.word 0x0068, tss1, 0xe900, 0x0    # TSS1 descr 0x30

在 0x1220 地址处
tss1:    .long 0             /* back link */
    .long krn_stk1, 0x10        /* esp0, ss0 */
    .long 0, 0, 0, 0, 0        /* esp1, ss1, esp2, ss2, cr3 */
    .long task1, 0x200        /* eip, eflags */
    .long 0, 0, 0, 0        /* eax, ecx, edx, ebx */
    .long usr_stk1, 0, 0, 0        /* esp, ebp, esi, edi */
    .long 0x17,0x0f,0x17,0x17,0x17,0x17 /* es, cs, ss, ds, fs, gs */
    .long LDT1_SEL, 0x8000000    /* ldt, trace bitmap */

x/10 0x1220, 观察, 发现正是 0xf:task1 = 0xf:0x2218, 而且 0x200 开启了IF, 使得运行任务1时中断便打开了。
而且, 任务切换,还会用tss0保留了现场。 以供切回tss0 时使用,这些都是硬件直接完成的!
从此,任务要在tss1 下运行一个时间片。 此时用户使用的堆栈是usr_stk1.
可见100个任务需要设置100个内核栈,100个用户栈.且互相不可重叠,才不会乱!
----------------------------------------
7. 其它问题:
问:任务被切走, 中断的iret 何时执行?
答:要等任务再被切换回的时候,当切走时,就是切换任务的下一条指令地址,被保留进TSS的EIP寄存器处,恢复时,还从那恢复。

   还恢复了一堆別的寄存器,接着就可以走后面的iret 指令了,

 我也是通过debug 跟踪理解的. 当时一个ljmp 跳走了,还以为走不到 jmp 2f,实际上它还是能回来的.

   只所以难理解,任务切换实际上除了第一次是跳到任务中开始处,其它都是跳转

   到中断程序中任务切换的下一条指令,即ljmp的下一条指令, 那里是后续的接头!!


问: 这样说,用户进程被时钟打断后,中断服务程序要执行很久才能走完了,不是中断服务程序
    执行的越短越好吗?!
答: 这个问题要分开来说,

     从用户的角度看, 程序被中断了,中断服务程序执行了很久(它被切换执行别的任务了),然后才返回来(通过iret返回)。.
    从系统的角度看,程序被中断以后,中断服务程序首先发送EOI 允许后续硬件中断请求,然后进行任务切换,切换是从新任务段中恢复中断标志,中断使能再次打开,可以认为中断服务已经完成.


    这里,我们从两个角度,解释了什么叫中断服务程序,侧重面不同。一个说再次打开中断为服务完成,一个说重回我程序为服务完成.角度不同.但描述的是不同侧面.

    这就是多任务切换的实质 . 单任务中断程序中断了很快返回,多任务被中断程序中断后引起任务切换,等轮到你的时候再返回.
 

小结1: 每一个任务运行时使用了2个栈, 用户态运行时发生中断,中断服务程序使用了tss中定义的内核栈。

    时钟中断以及系统调用int80中断都使用这个内核栈。因为它们RPL都是0级(08的低2位)

    任务切换时,保留当前环境到当前tss, 从切换到的tss中恢复现场开始运行, 所有寄存器,段寄存器,
    常规寄存器,cr3, ldt 都被恢复。

小结2:

1. 什么是进程.
  进程是程序调入内存后的一个执行实例.每个进程拥有自己独立的资源,代码段,数据段,堆栈段.
  386可以用一个ldt表来描述,而这个ldt表,用gdt表中ldt描述符来描述.
  进程切换需要保留当前的进程状态,它将保留在一个任务状态段(TSS)中,并从被切换到的任务状态段中获取执行的上下文开始运行.
  任务状态段也用gdt表中一个描述符来描述,叫tss描述

 每个进程需要一个LDT描述符和一个TSS描述符,分别对应TSS表和LDT表.

TSS表用来保存现场.

LDT表用来定义代码段,数据段,堆栈段等.因为X86采用的是段式寻址方式.段+偏移方式


    考察这两个简单的进程,task0,task1,它们真是不能再简单了.
    需要有两个任务状态段tss0,tss1,用来保存任务切换时的寄存器内容, 这样在gdt表中需要加2个描述符
    每一个任务需要一个ldt描述符, 每一个ldt描述符对应一个ldt表,包含定义代码段,数据段描述符等,描述符的偏移就确定了 cs,ds,ss就是所谓的段式寻址,所以段式寻址编程先要设一堆表,而编译器其实只认别偏移地址

 

2. 任务状态段存在的必要性:
    任务状态段存在的必要性是因为intel cpu运行于内核态与运行于用户态都共用一套寄存器, 在任务切换时,需要保留它们,
    为了简化操作,开辟一块内存,用硬件一次性把寄存器内容存入其中,省去了用户在堆栈中保留一大堆寄存器的过程.
    这样用一条指令即能完成任务切换. ljump TSS0_SEL 或ljump TSS1_SEL, 长跳转到任务状态段1描述符或任务状态段2描述符
    这样自动完成ldt切换,恢复cs,ds,ss等段寄存器及常规寄存器,堆栈寄存器及其eip(代码执行位置).
    据说arm 内核态与用户态用两套寄存器,则没有了级别变化时保存寄存器这一拖累!不过任务切换还是要保留寄存器.

3. 第一次进入用户态运行,用的是iret指令

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

linux0.00 代码阅读笔记 的相关文章

  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 各种中断的区别:SCI、SMI、NMI、普通中断

    我正在学习英特尔架构 到目前为止我遇到过几种类型的中断 SCI 系统控制中断 硬件使用的系统中断 用于向操作系统通知 ACPI 事件 SCI 是一个有效 低电平 可共享的电平中断 SMI 系统管理中断 由遗留系统上的中断事件生成的操作系统透
  • 测量进程消耗的 CPU 时钟

    我用 C 语言编写了一个程序 它是作为研究结果创建的程序 我想计算程序消耗的确切 CPU 周期 精确的循环次数 知道我怎样才能找到它吗 The valgrind tool cachegrind valgrind tool cachegrin
  • Polygot 包含 nasm/yasm 和 C 的文件

    我有一堆幻数 我想将它们包含在由 nasm 或 yasm 编译的 C 程序和汇编文件中 在纯 C 语言中 该文件看起来像是一系列定义 例如 define BLESS 55378008 define ANSWER 42 在 nasm 或 ya
  • 在 x86 程序集中打印寄存器值的简单方法

    我需要在 8086 Assembly 中编写一个程序 接收来自用户的数据 进行一些数学计算并在屏幕上打印答案 我已经编写了程序的所有部分并且一切正常 但我不知道如何打印号码显示到屏幕上 在我所有计算结束时 答案是 AX 它被视为无符号 16
  • 比“add esp, 4”更小的指令

    又是我 我的程序中有很多 add esp 4 我正在尝试减小它的大小 是否有任何更小的指令可以替代 add esp 4 pop edx 或者您不介意破坏的任何其他整数寄存器 这就是现代编译器实际上所做的 https stackoverflo
  • 测试 xmm/ymm 寄存器是否为零的更快方法?

    It s fortunate that PTEST does not affect the carry flag but only sets the rather awkward ZF also affects both CF and ZF
  • 如何使 gcc 为 -fpatchable-function-entry 发出多字节 NOP?

    gcc确实有能力使用多字节用于对齐循环和函数的 NOP 然而当我尝试 fpatchable function entry option https gcc gnu org onlinedocs gcc Instrumentation Opt
  • 如何通过查看程序集来判断程序是否使用动态调度

    我在 Reddit 上读过一篇文章Herb Stutter JIT 永远不会像原生一样快 http www reddit com r programming comments rr2dj herb stutter jit will neve
  • 用python控制风扇速度并检测电脑内部温度?

    由于我的电脑风扇噪音很大 我想为自己编写一个程序 在不需要全速运行时 关闭它 我想用python制作它 那么有没有任何模块可以检测温度和 或设置风扇速度 不要使用 python 或 WMI 如果您使用的是 Windows 并且无法使用 sp
  • x86 汇编乘法和除法指令操作数,16 位及更高

    我对 x86 汇编中的乘法和除法运算如何工作感到相当困惑 例如 下面的代码看起来并不太困难 因为处理的是 8 位 8 位乘法 User Input num1 20 num2 15 mov ax num1 moves the 8 bits i
  • 让 GCC/Clang 使用 CMOV

    我有一个简单的标记值联合 这些值可以是int64 ts or doubles 我正在对这些联合进行加法 但需要注意的是 如果两个参数都代表int64 t值 那么结果也应该有一个int64 t value 这是代码 include
  • 如何让 gcc 生成合适的代码来检查缓冲区是否充满 NUL 字节?

    我正在实现一个解析磁带档案的程序 解析器逻辑的一部分是检查存档结束标记 该标记是一个充满 NUL 字节的 512 字节块 我为此编写了以下代码 希望 gcc 能对此进行很好的优化 int is eof block const char us
  • X86 汇编将小写字母转换为大写字母

    实现toUpper函数 将字符串中的小写字母转换 为大写 该函数采用一个参数 char string 字符串是一个 char类型指针 指向字符串的开头 因为C 样式字符串以零结尾 我们不需要取长度 字符串作为另一个参数 我需要帮助开始 我不
  • 添加饱和 32 位有符号整数内在函数?

    有人可以推荐一种使用 Intel 内在函数 AVX SSE4 添加饱和 32 位有符号整数的快速方法吗 我查看了内在指南并发现 mm256 adds epi16但这似乎只添加 16 位整数 我没有看到 32 位有任何类似的东西 其他电话似乎
  • 使用 XCHG 解锁的自旋锁

    维基百科提供的使用 x86 XCHG 命令的自旋锁的示例实现是 Intel syntax locked The lock variable 1 locked 0 unlocked dd 0 spin lock mov eax 1 Set t
  • 使用 GNU C 内联汇编在 VGA 内存中绘制字符

    我正在学习使用 C 和内联汇编在 DOS 中进行一些低级 VGA 编程 现在我正在尝试创建一个在屏幕上打印出字符的函数 这是我的代码 This is the characters BITMAPS uint8 t characters 464
  • __stack_chk_fail_local 和 -fno-stack-protector - 如何让它工作?

    Update 我刚刚发现问题出在我的项目 libxml2 中包含的预构建库上 它是在启用堆栈保护的情况下构建的 因此依赖于 stack chk fail local方法 我现在已经重建了该库 fno stack protector也是 一切
  • 汇编程序中的过程调用如何工作?

    我刚刚开始摆弄 ASM 我不确定我对过程调用的理解是否正确 假设代码中的某个时刻有一个过程调用 call dword ptr 123 该过程仅包含一个命令 ret ret 0004 该过程调用的效果是什么 返回值将存储在哪里 我在某处读到
  • 我可以使用 AVX FMA 单元进行位精确的 52 位整数乘法吗?

    AXV2 doesn t have any integer multiplications with sources larger than 32 bit It does offer 32 x 32 gt 32 http www felix

随机推荐

  • SD、SDIO和MMC接口基础和规范介绍

    在MMC规范发展的过程中出现了很多的名词 如SDHC SDIO SDXC等 每次看到这些不同的规范都有点懵 也很容易搞混 所以本篇文章就来介绍一下MMC规范发展过程中出现的一些新的规范 并详细地理解一下SD和SDIO 文章目录 1 MMC规
  • 【cdk的使用】C/C++ TCP 粘包 拆包 及解决方案

    Github地址 https github com wujin1989 cdk TCP因为没有边界 所以会有粘包的问题 看下面代码 server c include cdk h include
  • 怎样利用 python 学习爬虫?

    一文搞懂Python gt 爬虫需要学什么 附送课程 笔记 关于Python爬虫 我们需要学 1 Python基础语法学习 基础知识 首先 你需要熟悉Python的基本语法 包括变量 数据类型 条件语句 循环 函数等 2 对HTML页面的内
  • 后缀mcp用什么软件打开_如何打开MCP文件?

    下载通用文件查看器 File Magic 安装可选产品 File Magic Solvusoft EULA Privacy Policy Terms Uninstall 步骤1 尝试不同的软件程序 如果无法打开MCP文件 则可能没有在计算机
  • JS实现插入排序

    1 算法简介 插入排序的工作原理就是将未排序数据 对已排序数据序列从后向前扫描 找到对应的位置并插入 插入排序通常采用占位的形式 空间复杂度为O 1 因此 在从后向前扫描的过程中 需要反复的把已排序的元素逐步向后挪位 为新插入元素提供插入的
  • xpath案例-解析所有城市名称

    第一种方法把热门城市和所有城市分开来考虑 import requests from lxml import etree if name main headers User Agent Mozilla 5 0 Windows NT 10 0
  • MQTT协议学习:1、MQTT协议了解

    MQTT协议学习 1 MQTT协议了解 文章目录 MQTT协议学习 1 MQTT协议了解 1 前言 2 MQTT简介 1 概述 2 相关名称 3 协议应用 4 开源方案 3 适用于FreeRTOS的MQTT库 4 最后 1 前言 MQTT可
  • CNN模型之LeNet-5

    一 介绍 卷积神经网络是当前深度学习领域比较火的研究方法 其应用主要是在计算机视觉上 例如 图像分类 目标检测 人脸识别等等 并且已经在这些领域取得了相当大的成就 本文主要介绍卷积神经网络的开篇之作 LeNet 5 LeNet 5由Y Le
  • vue在线预览word、excel、PDF

    1 安装依赖 docx文档预览组件 npm install vue office docx vue demi 0 13 11 S excel文档预览组件 npm install vue office excel vue demi 0 13
  • P4 晶体管四种工作状态+静态分析【更新】

    gt 晶体管四种工作状态 放大 饱和 截止 倒置 gt 静态分析 定量分析晶体管处于何种工作状态 注意 不安全区暂时不用关注 倒置状态暂时也可以不关注 放大区 之所以称为放大区 因为在这个区域 iB 与iC满足放大beta倍的关系 这是表面
  • getopt函数(未更新完)

    2023年7月28日 周五上午 这是我目前碰到过的比较复杂的函数之一 为了彻底弄懂这个函数 我花了几个小时 为了更好的说明这个函数 之后我可能会录制讲解视频并上传到B站 如果我上传到B站 我会在文章添加视频链接的 内容太多了 没写完 有空再
  • java Logback输出日志内容到文件

    要将logger info的信息输出到文件 您可以使用Logback配置 下面是一个简单的示例 1 首先 在您的项目中添加Logback依赖 例如在Maven项目中的pom xml文件中添加以下代码
  • 基于OpenCV的交通标志识别(SVM+Hu不变矩, 部分测试源代码)

    最近跟着老师做一个交通识别的项目 总算明白了一个道理 这水啊 不去亲自蹚上一遭就不知道有多深 更根本的原因当然还是自己学的不够扎实 不够好 经过了一个寒假的折磨 终于做出了一个原型来 想到了自己当时被折磨的头疼的样子 想着将一部分源代码发上
  • 前端post请求中body和query传参的区别

    前端发送请求最常用的是get请求还有post请求 get请求只能传query参数 query参数都是拼在请求地址上的 post可以传body和query两种形式的参数 如下 编辑项目列表 export function editProjec
  • SeqGPT: 开箱即用的开放域自然语言理解大模型

    论文链接 SeqGPT An Out of the box Large Language Model for Open Domain Sequence Understanding https arxiv org abs 2308 10529
  • 【DL】血与泪的炼丹心得

    记录一些炼丹的心得 都是坑啊 以下都是经过很多实验得到的炼丹心得 希望对大家有帮助 模型很复杂 各种网络融合 尝试用更小的学习率和更多的epoch 学习率预热是个好东西 必须用上 学习率很重要 可以发掘模型的极限 但是无法改变模型的上限 模
  • DataAnalysis-Maggie-Lecture6-机器学习基础

    ML的基础框架 1定义要解决的问题 2构建数据集 3数据变换 4训练模型 5使用模型预测 example 垃圾邮件标记系统来解释术语 Dataset 一堆的邮件 Sample Instances 一封邮件 Feature Variables
  • springcloud微服务:nacos的配置说明与服务注册

    这部分我要知道两点就是nacos如何去注册服务和发现服务的 一 工程结构和版本依赖 首先要说一个我们的springcloud工程 基于半仙的springcloud工程 这个工程比较有意思 就是我很少看到pom文件一层套一层 相当于是三级po
  • 修改el-card的header的背景颜色

    修改el card的header的背景颜色 1 修改默认样式 好处是当前页面的所有的el card都会变化 页面卡片
  • linux0.00 代码阅读笔记

    汇编语言的编写 编译 运行 调试 author hjjdebug date 参考代码地址 GitHub hjjdebug linux0 00 linux0 00 code compiled under ubuntu14 04 gcc 4 8