vdso概念及原理,vdso_fault缺頁異常,vdso符號的獲取

一、背景

vdso的全稱是Virtual Dynamic Shared Object,它是一個特殊的共享庫,是在編譯內核時生成,并在內核鏡像里某一段地址段作為該共享庫的內容。vdso的前身是vsyscall,為了兼容一些舊的程序,x86上還是默認加載了vsyscall:

但是在arm64上并不支持vsyscall,也沒有這樣的程序段:

我們在做一些用戶態程序的棧的抓取時,有時候是會運行到vdso里去的,在x86上也甚至可能運行到vsyscall里去,這時候,我們也需要知道vdso里有哪些符號。

在下面第二章里,我們會介紹vdso的概念和原理,原理側重于介紹內核部分的相關邏輯,用戶態部分的會在后面的博客里介紹。另外,還會對vdso的代碼段的fault函數也就是vdso_fault函數進行介紹,并拓展到page的引用計數和vm_insert_page函數的使用。另外,也會介紹vvar_fault等也屬于vdso范疇的其他相關細節。

vdso可以用來做性能相關的優化,但是前提肯定是得先了解其原理。

二、vdso概念及實現原理,vdso_fault缺頁異常邏輯

2.1 vdso函數以時間獲取為主

在下面的第三章里,我們會將如何撈取vdso里的符號,我們把撈取到的內容展示一下:

x86下的vdso的符號多一些:

arm64下的vdso的符號少一些:

可以從上兩張圖里可以看到,無論是x86還是arm64,符號里基本都是和時間接口有關。

2.2 時間獲取走vdso的原因

原因是為了性能優化,因為時間獲取并不是一個敏感的信息,并不涉及很多安全考慮,另外,時間獲取的邏輯相對也較為簡單,并不依賴內核里的很多函數,這樣,把時間獲取有關的數據和代碼段映射到用戶態來執行也相對簡單。

如果時間獲取邏輯走了vdso,那么用戶態代碼在執行該時間獲取路基時就不需要陷入內核來執行,這很明顯能提升運行效率。因為每次系統調用陷入內核之后要做上下文切換,用戶棧和內核棧的保存和切換,另外在內核態代碼執行完后返回用戶態時也得做reschedule的判斷,更別提使能了rt-linux之后內核邏輯里如果用到了鎖還會更加一些調度有關的檢查和切換邏輯,這些都是消耗cpu的。

2.3 以時間獲取為例介紹vdso的實現原理

這一節我們介紹vdso的實現原理,以時間獲取為例來介紹。不過無論是哪個接口,底層這塊的vdso的邏輯都是一樣的,我們從底到上來介紹實現原理。

2.3.1 內核的vdso映射邏輯,vdso段和vvar段及測試ko

我們運行如下命令可以看到兩個vdso模塊會用到的地址段:

cat /proc/1/maps | grep -E "vdso|vvar"

我們上圖看到的是用戶態地址段,是進程1的用戶空間地址范圍,可以看到這兩個maps的條目比較特殊,是用"[]"來包裹的,事實上,內核里確實對其進行了特殊映射,相關函數是_install_special_mapping,如在x86時,在arch/x86/entry/vdso/vma.c里的map_vdso函數里有如下映射邏輯:

上圖里的vdso_mapping和vvar_mapping如下定義:

這里,[vdso]是.text段也就是代碼段,[vvar]是數據段內容,是用戶態和內核態共享維護的vdso邏輯相關的數據的地址段。

針對代碼段和數據段的缺頁異常有不同的.fault函數,代碼段的缺頁異常函數vdso_fault,我們使用一個ko代碼來kprobe這個vdso_fault來確定它的觸發點的調用堆棧并非來自于_install_special_mapping時同步觸發(同步觸發的場景只在映射時帶上MAP_POPULATE/MAP_LOCKED時才會同步觸發pagefault,在之前的博客?內存管理相關——malloc,mmap,mlock與unevictable列表-CSDN博客 里的 3.2.1 一節里講到),抓到的堆棧如下:

對于vvar_fault,抓到的堆棧如下,和vdso_fault是一樣的,不是同步觸發pagefault:

測試用的源碼:

#include <linux/module.h>
#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/lockdep.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <trace/events/workqueue.h>
#include <linux/sched/clock.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/tracepoint.h>
#include <trace/events/osmonitor.h>
#include <trace/events/sched.h>
#include <trace/events/irq.h>
#include <trace/events/kmem.h>
#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <linux/sched/task_stack.h>
#include <linux/nmi.h>
#include <asm/apic.h>
#include <linux/version.h>
#include <linux/sched/mm.h>
#include <asm/irq_regs.h>
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
#include <linux/stop_machine.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhaoxin");
MODULE_DESCRIPTION("Module for vdso_fault debug.");
MODULE_VERSION("1.0");struct kprobe _kp1;static bool _blog = false;int kprobecb_vdso_fault_pre(struct kprobe* i_k, struct pt_regs* i_p)
{if (!_blog) {_blog = true;dump_stack();}return 0;
}int kprobe_register_func_vdso_fault(void)
{int ret;memset(&_kp1, 0, sizeof(_kp1));_kp1.symbol_name = "vvar_fault";_kp1.pre_handler = kprobecb_vdso_fault_pre;_kp1.post_handler = NULL;ret = register_kprobe(&_kp1);if (ret < 0) {printk("register_kprobe fail!\n");return -1;}printk("register_kprobe success!\n");return 0;
}void kprobe_unregister_func_vdso_fault(void)
{unregister_kprobe(&_kp1);
}static int __init testvdso_init(void)
{kprobe_register_func_vdso_fault();return 0;
}static void __exit testvdso_exit(void)
{kprobe_unregister_func_vdso_fault();
}module_init(testvdso_init);
module_exit(testvdso_exit);

在接下來的三節里,我們依次來分析一下上面提到的vdso_fault,vvar_fault,_install_special_mapping三個函數。

2.4?vdso_fault缺頁異常邏輯,及get_page

表面上來看vdso_fault的函數實現,其實還是比較簡單的,就是判斷一個地址范圍,超出的話報VM_FAULT_SIGBUS錯誤,除此以外就獲取到vdso代碼段的page,增加該物理頁的引用計數:

如上圖里,核心邏輯其實就是兩步:設置vmf->page設置對應的物理頁,再調用get_page。

內核里相似的在缺頁異常里處理的做法如下圖:

但是事實上,雖然我們看到的只是簡單的兩步,但是缺頁異常的調用鏈上還是配合有很多其他邏輯的。

2.4.1 詳細跟蹤vdso_fault的調用鏈

我們回過來看一下vdso_fault相關的調用鏈:

根據里面的調用鏈里的函數的offset,結合vmlinux.txt(objdump -S出來的文件),我們得到上圖的調用鏈包含inline函數的完整調用鏈是:

handle_mm_fault->__handle_mm_fault->handle_pte_fault->do_pte_missing->do_fault->do_read_fault->__do_fault,拆解一下如下:

handle_mm_fault調用了__handle_mm_fault:

__handle_mm_fault調用了handle_pte_fault:

handle_pte_fault調用了do_pte_missing:

do_pte_missing調用了do_fault:

do_fault調用了do_read_fault:

do_read_fault調用了__do_fault:

2.4.2?do_read_fault里在執行完__do_fault后調用了finish_fault進行了頁表設置

詳細來說,就是在__do_fault函數里設置了vmf->page后,在finish_fault里根據vmf->page來進行pte的設置:

finish_fault里根據vmf的頁的標志位信息,如果是可寫且不共享的,則用vmf->cow_page,如果是其他情況,則用vmf->page:

finish_fault里用page和vma的信息來設置頁表和tlb:

2.4.3 關于缺頁異常里的使用的vmf_insert_pfn情形

在上面幾節搞清楚了vdso_fault的缺頁異常的流程里設置pte的操作是在vdso_fault的這個special vma的.fault函數執行之后做的這個細節之后,還有一個get_page的疑問,就是為什么在vdso_fault里有這樣的get_page的顯示的調用,而在別的缺頁異常的處理函數里,vm_insert_page或vmf_insert_pfn這樣的調用之后不需要再get_page調用了,我們依次看一下原因,先看vmf_insert_pfn的情形,如下圖例子:

如上圖看到,在執行完vmf_insert_pfn之后,返回了VM_FAULT_NOPAGE。這個VM_FAULT_NOPAGE表示什么含義呢?

它是表示缺頁異常處理函數里配置了新的PTE,這次缺頁異常并沒有返回一個新的頁面。既然不是新的頁面,那么也并不需要通過get_page來增加引用計數。

當return了VM_FAULT_NOPAGE之后,在do_read_fault里執行了__do_fault函數,拿到的返回值如果是VM_FAULT_NOPAGE時,如下圖,就會直接返回,并不會執行finish_fault的根據vmf->page進行pte配置的動作,這種情況,相關的pte動作都是在vmf_insert_pfn里執行的。

vmf_insert_pfn里執行相關pte配置的動作的截圖:

2.4.4?關于缺頁異常里的使用的vm_insert_page情形

上面一節里介紹的vmf_insert_pfn是直接拿著頁框去做映射,缺頁異常里使用vmf_insert_pfn來做映射的情況也是非常常見的。另外,我們其實也可以用vm_insert_page或者vm_insert_pages函數是根據page結構體來去做映射。如下圖方式:

如上圖情況下,用的是vm_insert_page接口,從使用角度來說,這個vm_insert_page相對更方便,不用再去找頁框,有page就可以了。使用vm_insert_page的時候不需要再去get_page一下,因為vm_insert_page里已經有了get_page動作。

vm_insert_page里先是要檢查page的引用計數不能是0,這對應的是kmalloc這種分配接口,分配出來以后自然引用計數就不為0了,這個我們用一個測試ko來驗證,這個ko會在下面一節里介紹,另外,例子里也會使用vm_insert_page函數,也有一個用戶態的mmap改ko創建的dev的節點的對應的例子程序。

我們繼續分析vm_insert_page下面的邏輯:

看一下insert_page里,會調用insert_page_into_pte_locked:

insert_page_into_pte_locked里會調用get_page增加page的引用計數:

get_page:

2.4.5 關于page的引用計數和vm_insert_page的實驗

測試ko源碼:

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/slab.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhaoxin");
MODULE_DESCRIPTION("Module for kernel test fault.");
MODULE_VERSION("1.0");static void *kaddr;static vm_fault_t my_fault(struct vm_fault *vmf)
{struct vm_area_struct *vma = vmf->vma;int offset, ret;offset = vmf->pgoff * PAGE_SIZE;ret = vm_insert_page(vma, vmf->address, virt_to_page(kaddr + offset));if (ret)return VM_FAULT_SIGBUS;return VM_FAULT_NOPAGE;
}static const struct vm_operations_struct vm_ops = {.fault = my_fault,
};static int my_mmap(struct file *file, struct vm_area_struct *vma)
{//vma->vm_flags |= VM_MIXEDMAP;vm_flags_set(vma, VM_MIXEDMAP);vma->vm_ops = &vm_ops;return 0;
}static struct file_operations my_fops = {.owner        = THIS_MODULE,.mmap        = my_mmap,
};static struct miscdevice mdev = {.minor = MISC_DYNAMIC_MINOR,.name = "my_dev",.fops = &my_fops,
};static int __init my_init(void)
{kaddr = kzalloc(PAGE_SIZE * 3, GFP_KERNEL);for (int i = 0; i < 3; i++) {printk("page[%d]:count[%d]\n",i, page_count(virt_to_page(kaddr + PAGE_SIZE*i)));}return misc_register(&mdev);
}static void __exit my_exit(void)
{misc_deregister(&mdev);kvfree(kaddr);
}module_init(my_init);
module_exit(my_exit);

insmod之后,可以看到:

可以如上下圖看到k*alloc函數分配出來的每個page的引用計數都是1:

用戶態程序使用mmap來觸發缺頁異常:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>#define DEVICE "/dev/my_dev"
#define PAGE_SIZE 4096
#define NUM_PAGES 3int main() {int fd;void *mapped_memory;// 打開設備fd = open(DEVICE, O_RDWR);if (fd < 0) {perror("Failed to open device");return EXIT_FAILURE;}// 使用 mmap 映射設備mapped_memory = mmap(NULL, NUM_PAGES * PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);if (mapped_memory == MAP_FAILED) {perror("mmap failed");close(fd);return EXIT_FAILURE;}// 寫入數據const char *data = "Hello, mmap!";memcpy(mapped_memory, data, strlen(data) + 1); // +1 以包含字符串的終止符// 讀取數據char buffer[PAGE_SIZE];memset(buffer, 0, sizeof(buffer));memcpy(buffer, mapped_memory, sizeof(buffer));printf("Read from mmap: %s\n", buffer);// 解除映射munmap(mapped_memory, NUM_PAGES * PAGE_SIZE);close(fd);return EXIT_SUCCESS;
}

運行測試程序后,可以成功讀寫(說明缺頁異常的邏輯基本是正確的):

2.4.6 新版本內核設置VM_MIXEDMAP時需要用vm_flags_set接口

在linux-6.5版本上,使用vma->vm_flags會編譯報錯:

這是因為新版本內核設置VM_MIXEDMAP時需要用vm_flags_set接口。

下面就是找的一個相對舊的版本和相對新的版本的同樣函數里使用上的對比:

下圖左邊是linux-6.5,右邊是linux-source-5.19.0(都是fs/cramfs/inode.c里的cramfs_physmem_mmap函數):

2.5?vvar_fault函數的相關細節

x86下的vvar_fault會考慮多種情形:

根據上圖里的sym_offset來去匹配不同的vvar_page的種類。

如上圖,默認選擇的sym_vvar_start是sym_vvar_page。

這個sym_vvar_start和sym_vvar_page等其他種類的定義都是在vdso-image-64.c里定義的:

回過來看vvar_fault里的邏輯:

上圖里先通過page_to_pfn得到頁框pfn,再通過vmf_insert_pfn進行映射的邏輯其實在上面 2.4.3 里已經介紹過了。

2.6?_install_special_mapping的調用鏈,涉及execve系統調用

我們改寫一下 2.3.1 里的測試ko,kprobe這個_install_special_mapping函數,打印這個函數的調用棧情況,如下:

分析vmlinux之后得到:

exec_binprm->do_execveat_common->bprm_execve->exec_binprm->search_binary_handler->load_elf_binary->ARCH_SETUP_ADDITIONAL_PAGES宏->arch_setup_additional_pages

從execve系統調用出發:

然后運行do_execve:

然后調用到do_execveat_common:

然后調用bprm_execve:

bprm_execve調用了exec_binprm:

exec_binprm調用了search_binary_handler:

然后search_binary_handler調用了fmt->load_binary:

fmt->load_binary里的load_binary和load_elf_binary的映射關系:

繼續看load_elf_binary函數里:

load_elf_binary里調用了如下圖的ARCH_SETUP_ADDITIONAL_PAGES(bprm, elf_ex, !!interpreter):

ARCH_SETUP_ADDITIONAL_PAGES宏使用了arch_setup_additional_pages:

arch_setup_additional_pages調用了map_vdso_randomized(&vdso_image_64):

(這里面的vdso_image_64在下面第三章里會詳細介紹)

map_vdso_randomized調用了map_vdso:

map_vdso調用_install_special_mapping:

三、如何撈取vdso里的符號

在上面的 2.5 一節里有提到vdso-image-64.c里定義了vdso_image_64數組:

這個vdso_image結構體里的.data變量就是放的vdso的代碼段裸數據:

3.1 通過內核空間來獲取vdso代碼段內容

輸入如下命令:

cat /proc/kallsyms | grep vdso_image_64

得到如下圖:

我們通過之前的博客?獲取內存內容的幾種方法-CSDN博客 里的第五章里的ko的方法:

insmod testgetkmem.ko address=0xffffffff8e8010e0 size=8 filedir="output.txt"

讀到的這個地址的前8字節是0xffffffff8ee47000:

正好和:

cat /proc/kallsyms | grep raw_data

得到的一個raw_data的符號的數值一樣:

這個raw_data是小寫的d的符號,即如下圖里的raw_data的static數組:

我們再讀一下這個raw_data的內容是否和代碼里的一致,可以看到是一致的:

3.2 通過/dev/mem來讀取mmap到用戶空間的vdso代碼段的內容

在之前的博客?獲取內存內容的幾種方法-CSDN博客?里的第四章里也提及。

cat /proc/1/maps | grep vdso

?把grep到的vdso的段的起始地址轉換成10進制數,替換下面命令里skip=后面的數字:

dd if=/proc/1/mem of=vdso.so skip=140736471179264 ibs=1 count=8192

我們比較 3.1 導出的output.txt的md5sum和這個vdso.so的md5sum,如下圖是一樣的:

四、關于vsyscall和vvar及撈取它們符號的實驗

4.1 vsyscall相比vdso的劣勢

如第一章里描述所說,vsyscall是比vdso早的東西,vdso相比vsyscall改進了很多。

vdso本質上是一個elf目標文件,而vsyscall僅僅是代碼+數據。如何理解這句話呢,意思就是vdso這個模擬出來的一個elf目標文件有了elf的一些基本屬性,比如可以像so文件一樣按照進程顆粒度動態映射到進程地址空間中,所有所謂的PIC(Position-Independent Code)屬性,而vsyscall則是固定的一段內核空間的地址段,不可更改,常見的地址是起始于0xffffffffff60000,size是4096,如下圖:

由于映射的地址不變,所以它是非常不安全的,內核里也對其相關頁進行了保護,下面會講到vsyscall的內容是不可讀的,只可執行,是拿不出來的。

另外,vdso的內容是so的格式,而vsyscall的內容是二進制格式,這也是兩者的區別。

4.2?vsyscall符號的撈取

上面的vsyscall的maps里條目可以看到vsyscall的地址段是不可讀的,但是我們也可以通過設置grub把vsyscall設置成emulate模式,再配合修改下圖里的__PAGE_KERNEL_VVAR宏,紅色框出的部分改成__RW:

重編內核,來通過gdb dump來獲取。

我們也可以用上面 3.1 一節里差不多的方法:

然后用之前的博客?獲取內存內容的幾種方法-CSDN博客?里第五章集成的dumpkmem的工具來導出到文件vsyscall.bin里去:

dumpkmem 0xffffffff8f004000 4096 vsyscall.bin

然后,我們可以用如下命令把該bin文件objdump出可閱讀代碼:

objdump -b binary -Mintel,x86-64,addr64 -m i386:x86-64 --adjust-vma=0xffffffffff600000 -D vsyscall.bin > vsyscall.txt

上圖里的--adjust-vma后面的數值是vsyscall的代碼段的固定起始地址:0xffffffffff60000

看一下上面的命令導出到的vsyscall.txt文件里的內容:

如下圖里命令方式去grep一下看到相關的幾個syscall的開始的指令位置:

對應于源碼里(第一個vsyscall的syscall是PAGE_SIZE對齊,后面的兩個符號是1024字節對齊):

4.3 vvar數據段的撈取方法

vvar在上面 2.3 一節里講vdso原理也介紹過是用于用戶vdso相關用戶態和內核態代碼共享內存數據所需要的。

先確認vvar的size是多少(如下圖看到是4個page):

這四個page的size對應代碼里的位置:

上圖里的sym_vvar_start對應于下面的在_install_special_mapping時傳入的size參數:

雖然vvar地址段顯示的是可讀,但是實際還是讀不出來的(用上面 3.2 里的方法):

dd if=/proc/1/mem of=vvar.bin skip=140736471162880 ibs=1 count=8192

如下圖提示錯誤:

我們需要知道vvar的用的是哪個符號,通過kprobe來打印出相關邏輯的數值(相關邏輯的介紹在上面 2.5 一節里有介紹):

vvar用到的page除了__vvar_page以外,還有可能會用到namespace里的time_ns里的vvar_page:

當前我們沒用到,如kprobe里打出來的情況:

我們讀__vvar_page,我們可以直接讀內核空間里的相關vvar的page的內容,如下方式:

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901271.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901271.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901271.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux中的文件傳輸(附加詳細實驗案例)

一、實驗環境的設置 ①該實驗需要兩臺主機&#xff0c;虛擬機名稱為 L2 和 L3 &#xff0c;在終端分別更改主機名為 node1 和 node2&#xff0c;在實驗過程能夠更好分辨。 然后再重新打開終端&#xff0c;主機名便都更改了相應的名稱。 ②用 ip a 的命令分別查看兩個主機的 …

【從0到1學Elasticsearch】Elasticsearch從入門到精通(上)

黑馬商城作為一個電商項目&#xff0c;商品的搜索肯定是訪問頻率最高的頁面之一。目前搜索功能是基于數據庫的模糊搜索來實現的&#xff0c;存在很多問題。 首先&#xff0c;查詢效率較低。 由于數據庫模糊查詢不走索引&#xff0c;在數據量較大的時候&#xff0c;查詢性能很差…

圖論基礎理論

在我看來&#xff0c;想要掌握圖的基礎應用&#xff0c;僅需要三步走。 什么是圖&#xff08;基本概念&#xff09;、圖的構造&#xff08;打地基&#xff09;、圖的遍歷方式&#xff08;應用的基礎&#xff09; 只要能OK的掌握這三步、就算圖論入門了&#xff01;&#xff0…

詳細解讀react框架中的hooks

React Hooks 是 React 16.8 引入的一項革命性特性&#xff0c;它允許你在函數組件中使用狀態(state)和其他 React 特性&#xff0c;而無需編寫 class 組件。下面將詳細解讀 React Hooks 的核心概念、常用 Hooks 及其工作原理。 一、Hooks 的核心概念 1. 什么是 Hooks Hooks …

主機IP動態變化時如何通過固定host.docker.internal訪問本機服務

場景需求——主機IP動態變化時&#xff0c;通過固定的 http://host.docker.internal:11555 訪問本機服務&#xff0c;核心問題在于 host.docker.internal 的解析邏輯與動態IP的適配。以下是分步解決方案&#xff1a; 一、核心原理&#xff1a;host.docker.internal 的本質與局…

插值算法 - 最近鄰插值實現

目錄 1. 導入必要的庫 2. nearest_neighbor_interpolation 3. 測試代碼 數學原理 完整代碼 本文實現了基于最近鄰插值算法的圖像縮放功能。 它使用 Python 編寫,主要依賴于NumPy和PIL(Python Imaging Library)庫。 NumPy用于高效的數值計算,而PIL僅用于圖像的加載和…

windows中搭建Ubuntu子系統

windows中搭建虛擬環境 1.配置2.windows中搭建Ubuntu子系統2.1windows配置2.1.1 確認啟用私有化2.1.2 將wsl2設置為默認版本2.1.3 確認開啟相關配置2.1.4重啟windows以加載更改配置 2.2 搭建Ubuntu子系統2.2.1 下載Ubuntu2.2.2 遷移位置 3.Ubuntu子系統搭建docker環境3.1安裝do…

MySQL事務機制

目錄 原子性 持久性 隔離性 隔離級別(并發事務之間的關系) 讀未提交 讀已提交 可重復讀 串行化(最嚴格的隔離級別) 一致性 問題 不可重復讀性(已經提交的數據) 什么是臟讀問題(未提交的數據)? 幻讀 保存點 自動提交機制--autocommit 會話隔離級別與全局隔離級…

Cadence學習筆記之---直插元件的封裝制作

目錄 01 | 引 言 02 | 環境描述 03 | 操作步驟 04 | 結 語 01 | 引 言 在之前發布的Cadence小記中&#xff0c;已經講述了怎樣制作熱風焊盤&#xff0c;貼片(SMD)焊盤、通孔、過孔&#xff0c;以及貼片元件的封裝。 本篇關于Cadence的小記主要講如何制作直插元件的封裝。 …

【第四十周】文獻閱讀:用于檢索-增強大語言模型的查詢與重寫

目錄 摘要Abstract用于檢索-增強大語言模型的查詢與重寫研究背景方法論基于凍結LLM的重寫方案基于可訓練重寫器的方案重寫器預熱訓練&#xff08;Rewriter Warm-up&#xff09;強化學習&#xff08;Reinforcement Learning&#xff09; 創新性實驗結果局限性總結 摘要 這篇論文…

java學習總結(if switch for)

一.基本結構 1.單分支if int num 10; if (num > 5) {System.out.println("num 大于 5"); } 2.雙分支if-else int score 60; if (score > 60) {System.out.println("及格"); } else {System.out.println("不及格"); } 3.多分支 int…

yum的基本操作和vim指令

在我們的手機端或者Windows上下載軟件&#xff0c;可以在相應的應用商店或者官網進行下載&#xff0c;這樣對于用戶來說十分的方便和便捷。而在Linux上&#xff0c;也有類似的安裝方式&#xff0c;我們來一一了解一下。 Linux安裝軟件的3種方法 源代碼安裝 在Linux下安裝軟件…

C++ CUDA開發入門

CUDA開發筆記 文章目錄 CUDA開發筆記[toc]1 概述2 環境3 命令行編譯4 CMAKE引入CUDA5 vscode開發CUDA6 Qt中使用CUDA-CMake7 QMake配置CUDA8 核函數9 核函數調用9.1 核函數調用語法9.2 執行配置參數詳解9.3 關鍵調用步驟9.4 重要注意事項9.5 調用示例分析9.6 最佳實踐建議 10 線…

llm開發框架新秀

原文鏈接:https://i68.ltd/notes/posts/20250404-llm-framework3/ google開源ADK-Agent Development Kit 開源的、代碼優先的 Python 工具包&#xff0c;用于構建、評估和部署具有靈活性和控制力的復雜智能體項目倉庫:https://github.com/google/adk-python 2.6k項目文檔:Age…

VM——相機拍照失敗

1、問題&#xff1a;相機頻閃觸發&#xff0c;在MVS中正常出圖&#xff0c;在VM中出現拍照失敗 2、解決&#xff1a; 1、首先排查網絡設置&#xff08;巨幀是否設置&#xff09; 2、電腦的所有防火墻是否關閉 3、在MVS中恢復相機的設置參數為默認參數&#xff0c;刪除VM中的全…

【時頻譜分析】小波分析

算法配置頁面&#xff0c;也可以一鍵導出結果數據 報表自定義繪制 獲取和下載【PHM學習軟件PHM源碼】的方式 獲取方式&#xff1a;Docshttps://jcn362s9p4t8.feishu.cn/wiki/A0NXwPxY3ie1cGkOy08cru6vnvc

怎么免費下載GLTF/GLB格式模型文件,還可以在線編輯修改

? 現在非常流行glb格式模型&#xff0c;和gltf格式文件&#xff0c;可是之類模型網站非常非常少 1&#xff0c;咱們先直接打開http://glbxz.com 官方glb下載網站 glbxz.com 2 可以搜索&#xff0c;自己想要的模型關鍵詞 3&#xff0c;到自己想下載素材頁面 4&#xff0c;…

【6】深入學習http模塊(萬字)-Nodejs開發入門

深入學習http模塊 前言http一個Web服務器項目創建代碼運行代碼解析 Server屬性&#xff1a;keepAlive屬性&#xff1a;keepAliveTimeout屬性&#xff1a;maxHeaderSize屬性&#xff1a;requestTimeout屬性&#xff1a;maxRequestsPerSocket方法&#xff1a;close()方法&#xf…

buuctf sql注入類練習

BUU SQL COURSE 1 1 實例無法訪問 / Instance cant be reached at that time | BUUCTF但是這個地方很迷惑就是這個 一個 # 我們不抓包就不知道這個是sql注入類的判斷是 get 類型的sql注入直接使用sqlmap我們放入到1.txt中 目的是 優先檢測 ?id1>python3 sqlmap.py -r 1.t…

(即插即用模塊-特征處理部分) 三十二、(TGRS 2024) MDAF 多尺度雙表示對齊過濾器

文章目錄 1、Multiscale Dual-Representation Alignment Filter2、代碼實現 paper&#xff1a;SFFNet: A Wavelet-Based Spatial and Frequency Domain Fusion Network for Remote Sensing Segmentation Code&#xff1a;https://github.com/yysdck/SFFNet 1、Multiscale Dual-…