nasm - BasicWindow_64
文章目录
- nasm - BasicWindow_64
- 概述
- 笔记
- my_build.bat
- nasm_main.asm
- END
nasm - BasicWindow_64
概述
学习网上找到的demo.
x64和x86的汇编源码还差挺多的。
x64的汇编代码不好写,细节整不对,程序就不运行。
如果要查为啥不运行,也要看和正向生成的C工程的反汇编代码有哪些区别,才看的出来。
LEA, MOV很容易弄混。
MOV时,是否该加 地址数据类型的修饰(e.g. qword, dword), 这些也是细节。
感觉真是有需求用反汇编实现关键函数时,也是要以正向的代码生成的反汇编代码的基础上小步快跑的改,才不至于改了一坨后跑不起来。
笔记
my_build.bat
@echo off
clsrem ----------------------------------------
rem my_build.batrem env
rem NASM version 2.16.03 compiled on Apr 17 2024
rem GoLink.Exe Version 1.0.4.6 Copyright Jeremy Gordon 2002-2025set path=C:\Program Files\NASM;C:\soft\Golink;%path%rem . bat默认是不支持中文的 .
rem echo full path name - %~f0
rem echo full path - %~dp0
rem echo file name - %~nx0
rem echo work path - %cd%
rem all param - %*rem . rem注释的第1个字符和最后1个字符,不能是中文,否则有概率会当作命令来执行 .
rem . 调试.bat的方法 .
rem . 如果.bat写的不对,又不容易看出来,只能在每行后面加pause, 然后执行.bat, 然后按一下空格执行一行 .set prj_src_name_1=nasm_main.asm
set prj_obj_name_1=nasm_main.obj
set prj_exe_name=BasicWindow_64.exerem win32 or win64
set prj_build_type=win64rem /console or /SUBSYSTEM:WINDOWS
set prj_sub_sys=/SUBSYSTEM:WINDOWSecho [%~nx0 %*]if "%1" == "build" (call :fn_build
) else if "%1" == "clear" (call :fn_clear
) else (call :fn_usage
)goto endrem ----------------------------------------
rem function
rem ----------------------------------------:fn_usage
echo usage my_build.bat [option]
echo build - build asm to EXE
echo clear - clear trush on the project
exit /brem ----------------------------------------
:fn_build
echo build ...rem find file on work path
call :fn_del_file "%prj_obj_name_1%"nasm -f %prj_build_type% %prj_src_name_1% -o %prj_obj_name_1%
rem 用IDA打开.obj 已经可以看到实现逻辑了call :fn_del_file "%prj_exe_name%"rem 如果不指定要连接的dll, 会报错
golink /entry:fn_Start '%prj_sub_sys%' kernel32.dll user32.dll %prj_obj_name_1% /fo %prj_exe_name%call :fn_exec "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_clear
echo clear ...
call :fn_del_file "%prj_obj_name_1%"
call :fn_del_file "%prj_exe_name%"
exit /brem ----------------------------------------
:fn_del_file
if exist "%~1" (echo del "%~1" del "%~1"
)
exit /b:fn_exec
if exist "%~1" (echo exec "%~1"%~1
)
exit /brem ----------------------------------------
:end
echo END
rem pause
call cmd
nasm_main.asm
; @file nasm_main.asm
; @brief 用NASM实现一个64bits的基本窗口
; nasm - BasicWindow_64
; ----------------------------------------
; 宏定义
; ----------------------------------------
; Basic Window, 64 bit. V1.01
COLOR_WINDOW EQU 5 ; Constants
CS_BYTEALIGNWINDOW EQU 2000h
CS_HREDRAW EQU 2
CS_VREDRAW EQU 1
CW_USEDEFAULT EQU 80000000h
IDC_ARROW EQU 7F00h
IDI_APPLICATION EQU 7F00h
IMAGE_CURSOR EQU 2
IMAGE_ICON EQU 1
LR_SHARED EQU 8000h
NULL EQU 0
SW_SHOWNORMAL EQU 1
WM_DESTROY EQU 2
WS_EX_COMPOSITED EQU 2000000h
WS_OVERLAPPEDWINDOW EQU 0CF0000hWindowWidth EQU 640
WindowHeight EQU 480
; ----------------------------------------
; 导入函数声明
; ----------------------------------------
extern CreateWindowExA ; Import external symbols
extern DefWindowProcA ; Windows API functions, decorated
extern DispatchMessageA
extern ExitProcess
extern GetMessageA
extern GetModuleHandleA
extern IsDialogMessageA
extern LoadImageA
extern PostQuitMessage
extern RegisterClassExA
extern ShowWindow
extern TranslateMessage
extern UpdateWindow
; ----------------------------------------
; 区段定义
; ----------------------------------------
; 函数的入口名称是啥都可以, 只要link的时候指定主函数是啥
global fn_Start ; Export symbols. The entry pointsection .data ; Initialized data segmentWindowName db "Basic Window 64", 0ClassName db "Window", 0section .bss ; Uninitialized data segmenthInstance resq 1section .text ; Code segment
; ----------------------------------------
; 函数实现
; 如果对x64汇编不熟,可以先写一个x86版的NASM工程,正常用了,再改一个x64工程出来,比较简单,不用想事
; ----------------------------------------
fn_Start:sub RSP, 8 ; // 16对齐SUB RSP, 32XOR RCX, RCXcall GetModuleHandleAmov [hInstance], RAXADD RSP, 32call fn_WinMain; .LB_Exit:
XOR RCX, RCX
call ExitProcess
ret
; ----------------------------------------
fn_WinMain:
; 如果函数内有局部变量,需要自己开栈空间
; EBP - X 是局部变量
; EBP + X 是入参push RBP ; Set up a stack framemov RBP, RSPsub RSP, 136 + 8 ; 136 bytes for local variables. 136 is not; a multiple of 16 (for Windows API functions),; the + 8 takes care of this.%define wc RBP - 136 ; WNDCLASSEX structure, 80 bytes
%define wc.cbSize RBP - 136 ; 4 bytes. Start on an 8 byte boundary
%define wc.style RBP - 132 ; 4 bytes
%define wc.lpfnWndProc RBP - 128 ; 8 bytes
%define wc.cbClsExtra RBP - 120 ; 4 bytes
%define wc.cbWndExtra RBP - 116 ; 4 bytes
%define wc.hInstance RBP - 112 ; 8 bytes
%define wc.hIcon RBP - 104 ; 8 bytes
%define wc.hCursor RBP - 96 ; 8 bytes
%define wc.hbrBackground RBP - 88 ; 8 bytes
%define wc.lpszMenuName RBP - 80 ; 8 bytes
%define wc.lpszClassName RBP - 72 ; 8 bytes
%define wc.hIconSm RBP - 64 ; 8 bytes. End on an 8 byte boundary%define msg RBP - 56 ; MSG structure, 48 bytes
%define msg.hwnd RBP - 56 ; 8 bytes. Start on an 8 byte boundary
%define msg.message RBP - 48 ; 4 bytes
%define msg.Padding1 RBP - 44 ; 4 bytes. Natural alignment padding
%define msg.wParam RBP - 40 ; 8 bytes
%define msg.lParam RBP - 32 ; 8 bytes
%define msg.time RBP - 24 ; 4 bytes
%define msg.py.x RBP - 20 ; 4 bytes
%define msg.pt.y RBP - 16 ; 4 bytes
%define msg.Padding2 RBP - 12 ; 4 bytes. Structure length padding%define hWnd RBP - 8 ; 8 bytes
; 在函数内 %define x, 当使用x时,只在函数内生效mov dword [wc.cbSize], 80mov dword [wc.style], CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOWLEA RAX, [REL fn_WndProc] mov qword [wc.lpfnWndProc], RAXmov qword [wc.cbClsExtra], NULLmov qword [wc.cbWndExtra], NULLmov RAX, qword [REL hInstance]mov qword [wc.hInstance], RAXsub RSP, 32 + 16 ; // x64调用函数时,必须留shadow space, 这是x64函数调用约定,阴影区size = 32 = 4 x 8 = (size RCX + RDX + R8 + R9)mov qword [RSP + 32 + 1 * 8], LR_SHARED ; // param6mov qword [RSP + 32 + 0 * 8], NULL ; // param5XOR R9, R9 ; // param4mov R8, IMAGE_ICON ; // param3mov RDX, IDI_APPLICATION ; // param2XOR RCX, RCX ; // param1call LoadImageAmov [wc.hIcon], RAXadd RSP, 32 + 16; 调用WinApi时,是被调用者平衡堆栈(阴影区 + 入参)sub RSP, 32 + 16mov qword [RSP + 32 + 1 * 8], LR_SHAREDmov qword [RSP + 32 + 0 * 8], NULLXOR R9, R9MOV R8, IMAGE_CURSORMOV RDX, IDC_ARROWXOR RCX, RCXcall LoadImageAmov qword [wc.hCursor], RAXadd RSP, 32 + 16mov qword [wc.hbrBackground], COLOR_WINDOW + 1mov qword [wc.lpszMenuName], NULLLEA RAX, [REL ClassName]mov qword [wc.lpszClassName], RAX; 小图标内装的也是大图标...sub RSP, 32 + 16mov qword [RSP + 5 * 8], LR_SHAREDmov qword [RSP + 4 * 8], NULLmov R9, NULLmov R8, IMAGE_ICONmov RDX, IDI_APPLICATIONXOR ECX, ECXcall LoadImageA ; Small program iconmov qword [wc.hIconSm], RAXadd RSP, 32 + 16sub RSP, 32lea RCX, [wc]call RegisterClassExAadd RSP, 32; 假设操作数为x; [x] 代表x的地址; x 代表x是一个立即数; [REL x] 是相对RIP的地址,支持重定位, [x]是绝对地址,不支持重定位; 所以要优先考虑使用 [REL x] 这样的用法; mov [hWnd], RAX 和 mov qword [hWnd] 的区别; mov [hWnd], RAX 依赖于编译器推断, 在复杂寻址或者代码优化后可能不靠谱; 既然已经是汇编了, 还是最好是显势指定地址类型, e.g. mov qword [hWnd]; push qword [hInstance] 强制将hInstance的地址作为qword类型,不安全, 如果hInstance的类型size < sizeof(qword), 风险就来了; push [hInstance] 会自动扩展, 安全,优先使用这种来压栈; 但是 NASM中,push一个地址中的内容时,必须指定数据类型的size; 所以,如果一个数据地址的类型不是qwrod, 必须先载入寄存器(进行数据扩展,高端字节扩展为0),再将寄存器入栈; 如果 hWnd 是定义在栈上变量的别名,MOV RCX, [REL hWnd] 就是错误的,因为REL 是相对于RIP的相对便宜。; 应该用 MOV RCX, [hWnd]; LEA 地址的操作, MOV是数据的操作; e.g. lea RCX, [msg] 等价语句为 mov RCX, msg; 不过最好操作地址还是用 lea, 因为可以用REL修饰改为产生相对地址。; x64程序,参数的压入,最好使用手工调整RSP, 避免栈中数据不对齐和其他风险.; 入参在影子区后面(影子区结尾 = RSP + 32); parma1 = RSP + 32 + 0 *8; parma2 = RSP + 32 + 1 *8; parma3 = RSP + 32 + 2 *8; 准备调用 CreateWindowExA,入参12个, 4个在寄存器(RCX,RDX,R8,R9),其余8个需要入栈sub RSP, 32 + (8 * 8)mov qword [RSP + 32 + (7 * 8)], NULLmov RAX, qword [REL hInstance]mov qword [RSP + 32 + (6 * 8)], RAXmov qword [RSP + 32 + (5 * 8)], NULLmov qword [RSP + 32 + (4 * 8)], NULLmov qword [RSP + 32 + (3 * 8)], WindowHeightmov qword [RSP + 32 + (2 * 8)], WindowWidthmov dword [RSP + 32 + (1 * 8)], CW_USEDEFAULTmov dword [RSP + 32 + (0 * 8)], CW_USEDEFAULTmov R9, WS_OVERLAPPEDWINDOWLEA R8, [REL WindowName]LEA RDX, [REL ClassName]mov RCX, WS_EX_COMPOSITEDcall CreateWindowExAmov [hWnd], RAXadd RSP, 32 + (8 * 8) ; // 平衡栈指针, 阴影区 + 入参的8个参数(不算RCX, RDX, R8, R9)SUB RSP, 32MOV RDX, SW_SHOWNORMALMOV RCX, [hWnd]call ShowWindowADD RSP, 32SUB RSP, 32mov RCX, [hWnd]call UpdateWindowADD RSP, 32.LB_MessageLoop:SUB RSP, 32XOR R9, R9XOR R8, R8XOR RDX, RDXLEA RCX, [msg]call GetMessageAADD RSP, 32cmp EAX, 0je .LB_Fn_EndSUB RSP, 32LEA RDX, [msg]MOV RCX, [hWnd]call IsDialogMessageAADD RSP, 32cmp EAX, 0jne .LB_MessageLoop ; Skip TranslateMessage and DispatchMessageSUB RSP, 32LEA RCX, [msg]call TranslateMessageADD RSP, 32SUB RSP, 32lea RCX, [msg]call DispatchMessageAADD RSP, 32jmp .LB_MessageLoop; .LB_X 这种在函数内的标签的,作用域只在函数内
; 多个函数内,可以有多个同名的标签
; 所以函数内的标签一定要以.开头
.LB_Fn_End:mov RSP, RBP ; Remove the stack framepop RBPxor RAX, RAXret
; ----------------------------------------
fn_WndProc:push RBP ; Set up a Stack framemov RBP, RSP; 用RBP来标记入参比较好
; 入参开始栈地址为(RBP + 16)的原因, 因为进了函数栈顶是返回地址(+8), 然后又保存了RBP(+8)
; 此时RBP + 16 才是入参开始地址
%define hWnd RBP + 16 + (0 * 8) ; Location of the 4 passed parameters from
%define uMsg RBP + 16 + (1 * 8) ; the calling function
%define wParam RBP + 16 + (2 * 8) ; We can now access these parameters by name
%define lParam RBP + 16 + (3 * 8); 将前4个参数从寄存器写入阴影区, 然后就可以自由使用4个寄存器了,也可以从阴影区读取前4个入参了
MOV qword [hWnd], RCX
MOV qword [uMsg], RDX
MOV qword [wParam], R8
MOV qword [lParam], R9cmp qword [uMsg], WM_DESTROY ; [EBP + 12]je .LB_WMDESTROY; .LB_DefaultMessage:SUB RSP, 32MOV R9, qword [lParam]MOV R8, qword [wParam]MOV RDX, qword [uMsg]MOV RCX, qword [hWnd]call DefWindowProcAADD RSP, 32jmp .LB_fn_end.LB_WMDESTROY:SUB RSP, 32XOR RCX, RCXcall PostQuitMessageADD RSP, 32xor EAX, EAX.LB_fn_end:mov RSP, RBPpop RBPret
; ----------------------------------------; 如果先写好一个x86版本的实现,再从x86版改出一个x64版,挺麻烦的,容易搞错(x86和x64的汇编代码,其实差的还是挺多的,改还不如重写)
; 还是用VS2019写一个工程,编译成release + x64(关掉SDL,不优化),然后用IDA看,将需要的部分摘出来整理比较方便。
; NASM的代码实现和VS2019反汇编的代码基本一致,搬过来改,要方便的多。
END
相关文章:
nasm - BasicWindow_64
文章目录 nasm - BasicWindow_64概述笔记my_build.batnasm_main.asmEND nasm - BasicWindow_64 概述 学习网上找到的demo. x64和x86的汇编源码还差挺多的。 x64的汇编代码不好写,细节整不对,程序就不运行。 如果要查为啥不运行,也要看和正向…...
SpringBoot:SSL证书部署+SpringBoot实现HTTPS安全访问
一、前言 SSL协议介于TCP/IP协议栈的第四层(传输层)和第七层(应用层)之间,为基于TCP的应用层协议(如HTTP)提供安全连接。它通过在客户端和服务器之间建立一个加密的通道,确保数据在传…...
selenium爬取苏宁易购平台某产品的评论
目录 selenium的介绍 1、 selenium是什么? 2、selenium的工作原理 3、如何使用selenium? webdriver浏览器驱动设置 关键步骤 代码 运行结果 注意事项 selenium的介绍 1、 selenium是什么? 用于Web应用程序测试的工具。可以驱动浏览…...
Spark提交任务
1、Spark提交任务到Yarn 1.1、DwKuduApp spark-submit --class com.io.etl.dwkudu.DwKuduApp \ --files /etl/etl-dwkudu/conf/doris.property,/etl/etl-dwkudu/conf/redis.property,/etl/etl-dwkudu/conf/log4j.property \ --master yarn --deploy-mode cluster \ --driver-…...
游戏引擎学习第113天
仓库:https://gitee.com/mrxiao_com/2d_game_2 黑板:优化的基本过程 在游戏编程中,优化是一个非常重要的学习内容,尤其是想要成为专业开发者时。优化的核心是理解代码的执行速度,以及如何提升其性能。在这个阶段,已经…...
token是什么
在自然语言处理(NLP)和机器学习的背景下,token 是指模型在处理文本时的最小单位。通常,这个单位可以是单词、字符,或者词的一部分。具体来说,token 的定义取决于你使用的模型和它的分词方式。 举个例子&am…...
23. AI-大语言模型-DeepSeek赋能开发-Spring AI集成
文章目录 前言一、Spring AI 集成 DeepSeek1. 开发AI程序2. DeepSeek 大模型3. 集成 DeepSeek 大模型1. 接入前准备2. 引入依赖3. 工程配置4. 调用示例5. 小结 4. 集成第三方平台(已集成 DeepSeek 大模型)1. 接入前准备2. POM依赖3. 工程配置4. 调用示例…...
IPv6报头40字节具体怎么分配的?
目录 IPv6报头结构 字段详解 示例代码:IPv6报头的Python实现 输出示例 IPv6协议是为了解决IPv4地址耗尽问题而设计的下一代互联网协议。与IPv4相比,IPv6不仅提供了更大的地址空间,还简化了报头结构,提高了网络设备的处理效率。…...
驱动开发、移植
一、任务明确:把创龙MX8的驱动 按照我们的要求 然后移植到 我们的板子 1.Linux系统启动卡制作, sd卡 先按照 《用户手册—3-2-Linux系统启动卡制作及系统固化》 把创龙的Linux系统刷进去。 2. 把TLIMX8-EVM的板子过一遍 把刚刚烧好系统的sd卡插入 创…...
BFS与Flood Fill:算法原理、实现细节与复杂度分析
目录 1. 概述 2. BFS 的基本原理 3. Flood Fill 算法 4. BFS 实现 Flood Fill 的步骤 5. C 实现 6. 代码解析 7. 复杂度分析 8. 应用场景 总结 1. 概述 Flood Fill 算法是一种用于填充封闭区域的算法,常用于图像处理、绘图工具和游戏开发中。BFS(…...
计算机网络基础杂谈(局域网、ip、子网掩码、网关、DNS)
目录 1. 简单局域网的构成 2. IP 地址 3. 子网掩码 4. IP地址详解自定义IP 5. IP 地址详解 6. 网关 7. DNS 域名解析 8. ping 1. 简单局域网的构成 交换机是组建局域网最重要的设备,换句话说,没有交换机就没法搭建局域网 交换机不能让局域网连…...
雷龙CS SD NAND(贴片式TF卡)测评体验
一、产品概述 近期获赠雷龙科技(Longsto)推出的CS系列贴片式SD NAND存储解决方案,包含两片工业级贴片式NAND芯片(CSNP16GCR01-AOW)及全兼容转接板。该方案支持TF卡形态扩展,实现高可靠性嵌入式存储应用。 …...
【Alertmanager】alertmanager告警系统原理剖析与应用实战,应有尽有非常全面
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…...
Java——权限修饰符
一、权限修饰符的继承访问规则 以下按访问范围从宽到窄排序: 修饰符同包同类同包子类同包非子类跨包子类跨包非子类public✔️✔️✔️✔️✔️protected✔️✔️✔️✔️❌默认(包级)✔️✔️✔️❌❌private✔️❌❌❌❌ 关键点…...
一周学会Flask3 Python Web开发-redirect重定向
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们学过渲染到模板页面,这个其实是一种内部的转发,浏览器地址栏地址没有变化。如果我们想重定向…...
python面向对象:方法
1. 实例方法 实例方法用于操作实例变量,必须包含 self 参数。 class Person:def __init__(self, name):self.name namedef greet(self):print(f"Hello, my name is {self.name}")person1 Person("Alice") person1.greet() # 输出ÿ…...
物联网简介集合
物联网(IoT)指的是物理设备(如电器和车辆)之间的互联互通。这些设备嵌入了软件、传感器和连接功能,使其能够相互连接并交换数据。这项技术实现了从庞大的设备网络中收集和共享数据,为打造更高效、自动化的系…...
centos下使用pyenv管理python版本
在 CentOS 上安装 pyenv 和 pyenv-virtualenv,可以按照以下步骤进行操作: ps: centos7 最高适配到3.9.* 步骤 1:安装依赖 首先,确保你的系统中安装了必需的依赖项。你可以使用以下命令安装它们: [root ~]# yum gro…...
C++:类与对象,定义类和构造函数
#define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> using namespace std; //如何让定义一个类 // 封装 // 1、将数据和方法定义到一起。 // 2、把想给你看的数据给你看,不想给你看的封装起来。 通过访问限定符来实现 class Stack { public: //1.成…...
【Java消息队列】应对消息丢失、重复、顺序与积压的全面策略
应对消息丢失、重复、顺序与积压的全面策略 引言kafka消息丢失生产者消费者重复消费顺序消费消息积压生产者消费者其他RabbitMQ消息丢失生产者事务机制,保证生产者发送消息到 RabbitMQ Server发送方确认机制,保证消息能从交换机路由到指定队列保证消息在 RabbitMQ Server 中的…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...
