從0開始的操作系統手搓教程45——實現exec

目錄

建立抽象

實現加載

實現sys_execv


!!!提示:因為實現問題沒有測試。所以更像是筆記!

exec 函數的作用是用新的可執行文件替換當前進程的程序體。具體來說,exec 會將當前正在運行的用戶進程的進程體(包括代碼段、數據段、堆、棧等)替換為一個新的可執行文件的進程體。這樣,新的程序會接管當前進程的地址空間,繼續執行新程序的代碼,但該進程的 PID(進程ID)保持不變。也就是說,執行 exec 后,原來進程的地址空間被清除,并且新程序的內容會加載到同樣的進程中,繼續執行。

為什么需要實現 exec 呢?這個問題的答案與 shell 的工作方式密切相關。在實現一些簡單的命令時,我們使用了類似 if-else if 的結構來判斷并執行不同的命令。然而,這種方法存在很大的局限性。首先,它無法處理用戶輸入的新命令,因為我們不能預見到用戶會輸入什么命令,且每添加一個新命令就需要修改代碼并重新編譯。這種方式不僅繁瑣,而且無法應對外部程序的運行。

exec 的實現解決了這個問題。當 exec 被調用時,它允許用戶運行外部程序,而不需要修改 shell 本身的代碼。用戶輸入的命令會被解析,且通過 exec 函數加載并執行對應的外部程序,從而提供了更靈活的命令執行方式。

exec 是一個函數簇,包含多個相關的函數,區別主要在于如何表示程序對象以及是否傳入環境變量。例如,execv 函數就不需要傳入環境變量,但其他 exec 函數可能會接受額外的環境變量。

當調用 execv 時,如果執行成功,進程將直接跳轉到新程序,并不會返回,因此它沒有返回值。調用 execv 失敗時,它會返回 -1,并設置錯誤碼。這是因為 exec 執行新程序時,原進程的執行流被完全替換,進程不會再回到原來的位置,因而不需要像傳統函數那樣返回值。

建立抽象

我們先對exe文件做抽象:

extern void intr_exit(void);
typedef uint32_t Elf32_Word, Elf32_Addr, Elf32_Off;
typedef uint16_t Elf32_Half;
?
/* 32-bit ELF header */
struct Elf32_Ehdr {unsigned char e_ident[16]; // ELF identification bytesElf32_Half e_type; ? ? ? ? // Type of file (e.g., executable)Elf32_Half e_machine; ? ? ?// Machine architectureElf32_Word e_version; ? ? ?// ELF versionElf32_Addr e_entry; ? ? ? ?// Entry point addressElf32_Off e_phoff; ? ? ? ? // Program header offsetElf32_Off e_shoff; ? ? ? ? // Section header offsetElf32_Word e_flags; ? ? ? ?// Processor-specific flagsElf32_Half e_ehsize; ? ? ? // ELF header sizeElf32_Half e_phentsize; ? ?// Program header entry sizeElf32_Half e_phnum; ? ? ? ?// Number of program headersElf32_Half e_shentsize; ? ?// Section header entry sizeElf32_Half e_shnum; ? ? ? ?// Number of section headersElf32_Half e_shstrndx; ? ? // Section header string table index
};
?
/* Program header (segment descriptor) */
struct Elf32_Phdr {Elf32_Word p_type; ? // Segment type (e.g., PT_LOAD)Elf32_Off p_offset; ?// Offset in fileElf32_Addr p_vaddr; ?// Virtual address in memoryElf32_Addr p_paddr; ?// Physical address (unused)Elf32_Word p_filesz; // Size of segment in fileElf32_Word p_memsz; ?// Size of segment in memoryElf32_Word p_flags; ?// Segment flagsElf32_Word p_align; ?// Segment alignment
};
?
/* Segment types */
enum segment_type {PT_NULL, ? ?// Ignore segmentPT_LOAD, ? ?// Loadable segmentPT_DYNAMIC, // Dynamic loading informationPT_INTERP, ?// Name of dynamic loaderPT_NOTE, ? ?// Auxiliary informationPT_SHLIB, ? // ReservedPT_PHDR ? ? // Program header
};

這段代碼定義了32位ELF(Executable and Linkable Format)格式的結構體以及相關的常量,用于描述ELF文件的頭部和程序段的描述。具體來說,主要包括以下內容:

  1. Elf32_Ehdr: 該結構體表示ELF文件的頭部,包含了ELF文件的基本信息,如文件標識、類型、機器架構、入口地址、程序頭的偏移量等。具體字段的含義如下:

    • e_ident:ELF文件標識字節,用于標識文件類型和版本。

    • e_type:文件類型,表明ELF文件是可執行文件、共享庫文件還是其他類型。

    • e_machine:表示機器架構的字段,如x86、ARM等。

    • e_version:ELF版本,通常為1。

    • e_entry:程序入口點的地址。

    • e_phoff:程序頭部的偏移量,指向包含程序段信息的位置。

    • e_shoff:節頭部的偏移量,指向包含節信息的位置。

    • e_flags:處理器特定的標志。

    • e_ehsize:ELF頭部的大小。

    • e_phentsize:程序頭項的大小。

    • e_phnum:程序頭的數量。

    • e_shentsize:節頭項的大小。

    • e_shnum:節頭的數量。

    • e_shstrndx:節頭字符串表的索引。

  2. Elf32_Phdr: 該結構體表示ELF文件中的程序頭(segment descriptor),用于描述文件中的每個段。字段的含義如下:

    • p_type:段的類型,如可加載段、動態段等。

    • p_offset:段在文件中的偏移。

    • p_vaddr:段在內存中的虛擬地址。

    • p_paddr:段在物理內存中的地址(通常不使用)。

    • p_filesz:段在文件中的大小。

    • p_memsz:段在內存中的大小。

    • p_flags:段的標志,如可讀、可寫、可執行等。

    • p_align:段的對齊方式。

  3. segment_type:該枚舉定義了常見的段類型,如:

    • PT_NULL:表示忽略該段。

    • PT_LOAD:表示可加載的段(常見的代碼和數據段)。

    • PT_DYNAMIC:動態加載信息。

    • PT_INTERP:動態加載器的名稱。

    • PT_NOTE:輔助信息。

    • PT_SHLIB:保留段。

    • PT_PHDR:程序頭。

實現加載

/* Load a segment from a file into virtual memory at the specified address */
static bool segment_load(int32_t fd, uint32_t offset, uint32_t filesz,uint32_t vaddr) {uint32_t vaddr_first_page =vaddr & 0xfffff000; // First page of the virtual addressuint32_t size_in_first_page =PG_SIZE - (vaddr & 0x00000fff); // Size of the segment in the first pageuint32_t occupy_pages = 0;
?// If the segment doesn't fit in a single pageif (filesz > size_in_first_page) {uint32_t left_size = filesz - size_in_first_page;occupy_pages = ROUNDUP(left_size, PG_SIZE) + 1; // +1 for the first page} else {occupy_pages = 1;}
?// Allocate memory for the segment in the process's address spaceuint32_t page_idx = 0;uint32_t vaddr_page = vaddr_first_page;while (page_idx < occupy_pages) {uint32_t *pde = pde_ptr(vaddr_page); // Page directory entryuint32_t *pte = pte_ptr(vaddr_page); // Page table entry
?// Allocate memory if PDE or PTE doesn't existif (!(*pde & PG_P_1) || !(*pte & PG_P_1)) {if (!get_a_page(PF_USER, vaddr_page)) {return false;}}vaddr_page += PG_SIZE;page_idx++;}
?// Read the segment data from the file and load it into memorysys_lseek(fd, offset, SEEK_SET);sys_read(fd, (void *)vaddr, filesz);return true;
}
?

函數 segment_load 負責將一個可執行文件中的特定段加載到進程的虛擬內存中,它接收四個參數:文件描述符 fd,段在文件中的偏移量 offset,段大小 filesz,以及段應加載到的虛擬地址 vaddr。其中 filesz 命名雖然讓人容易聯想到整個文件大小,但它其實是 ELF 格式中段頭部的字段名 p_filesz,表示當前這個段在文件中的實際大小,因此用作參數名是為了與 ELF 中的結構保持一致。

段的加載實質上就是內核為新進程分配內存的過程。由于程序通常由多個段組成,內核需要對每個段逐一加載。加載時以頁為單位進行內存管理,因此即使一個段不滿一頁,也必須以頁為粒度分配內存。變量 vaddr_first_page 是將段的虛擬地址 vaddr 向下對齊到頁起始地址,用于確定從哪里開始分配頁框。而變量 size_in_first_page 則表示該段在第一頁中所占用的字節數,如果 filesz 大于這個值,說明段會跨頁,因此接下來計算還需多少頁框,最終由 occupy_pages 給出總的頁框數。

接下來是頁框分配邏輯,考慮到這是 exec 執行新程序的場景,當前進程的頁表結構還在用,若某虛擬地址已經存在對應的物理頁,則無需重新分配,只需直接復用原頁框覆蓋其內容即可;否則就通過 get_a_page 分配一個新頁框。分配時逐頁判斷并處理,直到整段的地址空間都被準備好。

頁框分配完成后,便可以真正加載段的數據了。首先使用 sys_lseek 將文件讀指針移動到段的起始偏移位置 offset,再用 sys_read 將長度為 filesz 的數據讀入到從 vaddr 開始的虛擬地址中。至此,這個段被完整加載進內存。整個過程體現了分段加載、按頁管理、懶分配頁框的設計思路,也保證了內存使用的靈活性與效率。

/* Load a user program from the filesystem by pathname, return entry point* address or -1 on failure */
static int32_t load(const char *pathname) {int32_t ret = -1;struct Elf32_Ehdr elf_header;struct Elf32_Phdr prog_header;k_memset(&elf_header, 0, sizeof(struct Elf32_Ehdr));
?int32_t fd = sys_open(pathname, O_RDONLY); // Open the program fileif (fd == -1) {return -1;}
?// Read the ELF header from the fileif (sys_read(fd, &elf_header, sizeof(struct Elf32_Ehdr)) !=sizeof(struct Elf32_Ehdr)) {ret = -1;goto done;}
?// Verify the ELF headerif (k_memcmp(elf_header.e_ident, "\177ELF\1\1\1", 7) ||elf_header.e_type != 2 || elf_header.e_machine != 3 ||elf_header.e_version != 1 || elf_header.e_phnum > 1024 ||elf_header.e_phentsize != sizeof(struct Elf32_Phdr)) {ret = -1;goto done;}
?Elf32_Off prog_header_offset = elf_header.e_phoff;Elf32_Half prog_header_size = elf_header.e_phentsize;
?// Iterate over all program headersuint32_t prog_idx = 0;while (prog_idx < elf_header.e_phnum) {k_memset(&prog_header, 0, prog_header_size);
?// Seek to the program header location in the filesys_lseek(fd, prog_header_offset, SEEK_SET);
?// Read the program header from the fileif (sys_read(fd, &prog_header, prog_header_size) != prog_header_size) {ret = -1;goto done;}
?// If the segment is loadable, load it into memoryif (PT_LOAD == prog_header.p_type) {if (!segment_load(fd, prog_header.p_offset, prog_header.p_filesz,prog_header.p_vaddr)) {ret = -1;goto done;}}
?// Move to the next program headerprog_header_offset += elf_header.e_phentsize;prog_idx++;}
?ret = elf_header.e_entry; // Return the entry point of the program
done:sys_close(fd); // Close the filereturn ret;
}
 

函數 load 的核心功能是加載一個 ELF 格式的用戶程序文件,并將其段映射到當前進程的虛擬地址空間中。如果加載成功,返回值是該程序的入口地址(即進程執行的起點);如果失敗,返回 ?1。

函數開始先聲明兩個結構體變量:elf_headerprog_header,分別用于保存 ELF 文件頭和程序段頭。在讀取 ELF 文件頭后(第 102 行),程序緊接著從第 108 行開始驗證 ELF 文件是否合法。

首先檢查的是 ELF 文件的魔數 e_ident[0-6],這 7 個字節應依次為:

  • 0x7F(用八進制 \177 表示)

  • 'E'(0x45)

  • 'L'(0x4C)

  • 'F'(0x46)

  • 1:32 位格式

  • 1:小端格式

  • 1:版本號

這幾項是 ELF 文件的標準標志,如果不匹配,說明該文件不是合法的 ELF 可執行文件。接下來還會檢查以下幾個字段:

  • e_type 是否為 ET_EXEC(值為 2,代表可執行文件)

  • e_machine 是否為 EM_386(值為 3,表示 x86 架構)

  • e_version 是否為 1(當前 ELF 版本)

  • e_phnum(程序頭數量)是否小于等于 1024

  • e_phentsize(每個程序頭條目的大小)是否等于 sizeof(Elf32_Phdr)

這些檢查都通過后,才認為這是一個有效的 ELF 可執行文件。

接下來,從 ELF 頭中讀取段頭信息的起始偏移地址 e_phoff,讀取到變量 prog_header_offset。段頭條目的字節大小 e_phentsize 賦給 prog_header_size,條目總數 e_phnum 用于控制接下來的循環。

然后從第 122 行進入循環,逐個讀取每個段頭。每次循環會先通過 sys_lseek 將文件指針跳到對應段頭位置,然后通過 sys_read 讀取一條段頭到 prog_header。第 136 行判斷該段是否是 PT_LOAD 類型,也就是是否是可加載段。如果是,就調用 segment_load,將該段的內容從文件加載到內存對應的虛擬地址。

所有段處理完畢后,從 ELF 頭中提取程序入口地址 e_entry 賦給返回值 ret,這表示程序開始執行的地址。

最后,無論是否加載成功,都會通過 sys_close 關閉打開的 ELF 文件,返回值為加載成功的入口地址或失敗的 ?1。

總體來說,load 函數的實現非常典型地體現了 ELF 格式的標準解析流程、段式加載方式、虛擬內存分配控制等關鍵內核概念,是內核啟動用戶進程的核心部分之一。

實現sys_execv

/* Replace the current process with the program at the specified path */
int32_t sys_execv(const char *path, const char *argv[]) {uint32_t argc = 0;while (argv[argc]) {argc++; // Count the number of arguments}
?// Load the program and get its entry pointint32_t entry_point = load(path);if (entry_point == -1) { // If loading failed, return -1return -1;}
?TaskStruct *cur = current_thread(); // Get the current running thread (process)k_memcpy(cur->name, path, TASK_NAME_ARRAY_SZ); // Update the process name
?// Update the stack with the argumentsInterrupt_Stack *intr_0_stack =(Interrupt_Stack *)((uint32_t)cur + PG_SIZE - sizeof(Interrupt_Stack));intr_0_stack->ebx = (int32_t)argv;intr_0_stack->ecx = argc;intr_0_stack->eip = (void *)entry_point;intr_0_stack->esp = (void *)KERNEL_V_START; // Set stack pointer to the highest// user space address
?// Jump to the entry point of the new processasm volatile("movl %0, %%esp; jmp intr_exit":: "g"(intr_0_stack): "memory");return 0;
}

sys_execv 函數的作用是將當前正在運行的進程替換為另一個可執行文件 path 所指定的程序,同時把參數數組 argv 一并傳給新程序。這個過程不會返回,一旦成功,當前進程就“變成”了另一個程序。

首先,函數會遍歷 argv,統計參數個數并存入變量 argc。接著調用 load(path) 試圖加載用戶程序,如果加載失敗(返回 -1),函數立即返回 -1。若加載成功,程序的入口地址會被保存下來,作為后續執行的跳轉目標。

之后,函數更新當前進程控制塊中的 name 字段,使其反映正在執行的新程序名,這樣在通過 ps 等工具查看時會顯示為新程序的名字。

然后獲取當前線程的內核棧頂地址。此時棧中存儲的是舊進程的中斷現場,但很快要把這些內容替換掉,準備啟動新進程。函數將參數個數 argc 寫入棧中保存的 ecx 寄存器位置,將參數數組 argv 的地址寫入 ebx 寄存器位置。因為 ebx 通常用于保存基地址,而 ecx 常用于計數,這是一種傳統習慣,也便于未來從運行庫中取參數。接著將程序入口地址寫入 eip,用于后續跳轉執行;再將用戶棧指針 esp 初始化為 0xc0000000,即用戶空間最高地址,以便新程序使用。

設置完成后,通過內聯匯編將 esp 寄存器修改為新的內核棧地址,并跳轉到 intr_exit。這個跳轉操作會恢復棧中保存的所有寄存器狀態,包括 eip、esp 和參數寄存器等,相當于“偽裝”從中斷中返回,從而進入新程序的執行流程。

因為這個過程是不可逆的,調用成功后不會返回到原來的函數中,所以 return 0 這一行永遠不會執行,它的存在只是為了避免編譯器報錯。整段代碼實現的是典型的 exec 功能,用一個新的程序完全替換當前進程的執行內容。

下一篇

從0開始的操作系統手搓教程46——實現wait和exit-CSDN博客文章瀏覽閱讀522次,點贊7次,收藏8次。實現exit和wait(筆記,因為實現問題沒有測試) https://blog.csdn.net/charlie114514191/article/details/146144946

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

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

相關文章

【python爬蟲】酷狗音樂爬取練習

注意&#xff1a;本次爬取的音樂僅有1分鐘試聽&#xff0c;僅作學習爬蟲的原理&#xff0c;完整音樂需要自行下載客戶端。 一、 初步分析 登陸酷狗音樂后隨機選取一首歌&#xff0c;在請求里發現一段mp3文件&#xff0c;復制網址&#xff0c;確實是我們需要的url。 復制音頻的…

Linux開發工具----vim

目錄 Linux編輯器-vim使用 1. vim的基本概念 正常/普通/命令模式(Normal mode) 插入模式(Insert mode) 底行模式(last line mode) 2. vim的基本操作 3. vim正常模式命令集 4. vim底行模式命令集 5. vim操作總結 (本篇文章相當于vim常用命令字典) Linux編輯器-vim使用 我們先來看…

基于云函數的自習室預約微信小程序+LW示例參考

全階段全種類學習資源&#xff0c;內涵少兒、小學、初中、高中、大學、專升本、考研、四六級、建造師、法考、網賺技巧、畢業設計等&#xff0c;持續更新~ 文章目錄 [TOC](文章目錄) 1.項目介紹2.項目部署3.項目部分截圖4.獲取方式 1.項目介紹 技術棧工具&#xff1a;云數據庫…

卷積神經網絡與計算機視覺:從數學基礎到實戰應用

卷積神經網絡與計算機視覺&#xff1a;從數學基礎到實戰應用 摘要 本文深入解析卷積神經網絡&#xff08;CNN&#xff09;的核心原理及其在計算機視覺中的應用。首先介紹卷積與互相關的數學定義及在神經網絡中的實際應用差異&#xff0c;接著從系統設計視角分析卷積的線性代數…

從Manus到OpenManus:多智能體協作框架如何重構AI生產力?

文章目錄 Manus&#xff1a;封閉生態下的通用AI智能體OpenManus&#xff1a;開源社區的閃速復刻挑戰與未來&#xff1a;框架落地的現實邊界當前局限性未來演進方向 OpenManus使用指南1. 環境配置2. 參數配置3. 替換搜索引擎4. 運行效果 協作框架開啟AI生產力革命 Manus&#xf…

js 使用 Web Workers 來實現一個精確的倒計時,即使ios手機鎖屏或頁面進入后臺,倒計時也不會暫停。

## 效果如上 <!-- 將 main.js 和 worker.js 放在同一個目錄下&#xff0c;然后在 HTML 文件中引入 main.js --><!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&q…

深入理解 Linux 中的 -h 選項:讓命令輸出更“人性化”

在 Linux 系統中&#xff0c;命令行工具是系統管理員和普通用戶最常用的交互方式之一。然而&#xff0c;命令行輸出往往充滿了技術性術語和數字&#xff0c;對于初學者或非技術用戶來說可能顯得晦澀難懂。幸運的是&#xff0c;許多 Linux 命令都提供了一個非常實用的選項&#…

Docker Compose國內鏡像一鍵部署dify

克隆代碼 git clone https://github.com/langgenius/dify.git進入docker目錄 cd docker修改.env部分 # 將環境模版文件變量重命名 cp .env.example .env # 修改 .env,修改nginx的host和端口,避免端口沖突 NGINX_SERVER_NAME192.168.1.223 NGINX_PORT1880 NGINX_SSL_PORT1443…

紅隊OPSEC(安全運營)個人總結

OPSEC又稱&#xff1a;運營安全&#xff0c;是指在紅隊的視角下&#xff0c;藍隊對我方的威脅。 OPSEC漏洞的五個流程&#xff1a; 關鍵信息識別&#xff1a;指紅隊的關鍵信息不泄露&#xff0c;包括但不限于紅隊的攻擊意圖&#xff0c;能力&#xff0c;人員&#xff0c;活動及…

NO.29十六屆藍橋杯備戰|string九道練習|reverse|翻轉|回文(C++)

P5015 [NOIP 2018 普及組] 標題統計 - 洛谷 #include <bits/stdc.h> using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);string s;getline(cin, s);int sz s.size();int cnt 0;for (int i 0; i < sz; i){if (isspace(s[i]))continue…

MongoDB 觸發器實現教程

在傳統的關系型數據庫&#xff08;如 MySQL&#xff09;中&#xff0c;觸發器是一種強大的工具&#xff0c;它可以在特定的數據庫操作&#xff08;如插入、更新或刪除&#xff09;發生時自動執行一段代碼。然而&#xff0c;MongoDB 并沒有原生內置的觸發器概念。不過&#xff0…

C#控制臺應用程序學習——3.11

一、整型數字計算 如果我們想執行以下程序&#xff1a;程序提示用戶輸入一個數字并輸出 num 20 的結果&#xff0c;我們的思維應該是這樣的&#xff1a; using System;public class Class1 {public static void Main(string[] args){Console.WriteLine("Enter the first…

【C語言】指針篇

目錄 C 語言指針概述指針的聲明和初始化聲明指針初始化指針 指針的操作解引用操作指針算術運算 指針的用途動態內存分配作為函數參數 指針與數組數組名作為指針通過指針訪問數組元素指針算術和數組數組作為函數參數指針數組和數組指針指針數組數組指針 函數指針函數指針的定義和…

嵌入式音視頻通話SDK組件EasyRTC:全平臺設備兼容,智能硬件里的WebRTC調用實踐

在萬物互聯時代&#xff0c;智能硬件設備對實時音視頻通信的需求呈現爆發式增長。傳統基于PC或移動端的WebRTC方案難以滿足嵌入式設備在資源占用、低延遲傳輸和硬件適配等方面的特殊需求。本文將深入探討如何通過EasyRTC嵌入式音視頻通信SDK在嵌入式設備中實現高效的WebRTC視頻…

Aim Robotics電動膠槍:機器人涂膠點膠的高效解決方案

在自動化和智能制造領域&#xff0c;機器人技術的應用越來越廣泛&#xff0c;而涂膠和點膠作為生產過程中的重要環節&#xff0c;也逐漸實現了自動化和智能化。Aim Robotics作為一家專注于機器人技術的公司&#xff0c;其推出的電動膠槍為這一領域帶來了高效、靈活且易于操作的…

c語言筆記 數組進階題目的理解

題目&#xff1a;聲明一個二維 int 型數組 a&#xff0c;再聲明另一個一維數組指針數組 b&#xff0c;使該數組 b 的每一個指針分別指向二維數組 a 中的每一個元素(即每一個一維數組)&#xff0c;然后利用數組 b 計算數組 a 的和。 圖解&#xff1a;畫圖幫助理解 我們要清楚什…

Photo Works在線圖片編輯器:一鍵修復老照片,輕松煥新記憶

★【概況介紹】 今天突然收到我的朋友電腦出故障了,截圖給我,我一看就知道這個是缺少必要的組件引起的故障。結合這個問題,我來談談自己的解決思路和方法,希望能夠幫助到大家。幫助大家是我最開心的事情。以前只是幫朋友解決問題,沒有記錄下來,剛剛接觸到這個平臺,剛好可…

FANformer:融合傅里葉分析網絡的大語言模型基礎架構

近期大語言模型(LLM)的基準測試結果引發了對現有架構擴展性的思考。盡管OpenAI推出的GPT-4.5被定位為其最強大的聊天模型&#xff0c;但在多項關鍵基準測試上的表現卻不及某些規模較小的模型。DeepSeek-V3在AIME 2024評測中達到了39.2%的Pass1準確率&#xff0c;在SWE-bench Ve…

【 IEEE出版 | 快速穩定EI檢索 | 往屆已EI檢索】2025年儲能及能源轉換國際學術會議(ESEC 2025)

重要信息 主會官網&#xff1a;www.net-lc.net 【論文【】投稿】 會議時間&#xff1a;2025年5月9-11日 會議地點&#xff1a;中國-杭州 截稿時間&#xff1a;見官網 提交檢索&#xff1a;IEEE Xplore, EI Compendex, Scopus 主會NET-LC 2025已進入IEEE 會議官方列表!&am…

藍橋杯練題順序

有重復,適當選擇題目~共229道題&#xff01; 后續會發題解~ STL&#xff1a;9 3100 反轉字符串 [string簡單]---3100 -CSDN博客 2470 單調棧 [stack簡單]---2470 單調棧 [stack簡單]-CSDN博客 2254 括號匹配&#xff01; [stack簡單]---2254: 括號匹配&#xff01;-CSDN博客 …