使用汇编语言实现memcpy
把内核放入内存,究竟需做什么
写满实现内核功能的代码的文件会被编译成一个ELF文件。这个ELF文件不同于LOADER BIN文件。后者实质是一个没有使用DOS命令的COM文件。因此,只需将它原封不动地从存储设备读入到内存中,然后跳转到这个内存区域的开始,就将CPU的控制权交给了LOADER。
ELF文件是当前Linux系统上的可执行文件格式。写一个C程序,然后编译成可执行文件,使用 file 查看这个文件,能看到这个文件是ELF文件。
ELF文件由program header table、elf header、section header table、section组成。只有elf header的位置是固定的,在elf文件的开始位置。其他几个成员的位置不固定。
将内核指令重新放置到内存中,需做两件事情:一、把内核文件读入内存中。二、把内存中的内核的程序段全部复制到规划好的内存位置。
第一件事情,熟悉FAT12文件系统,就能做到。我已经独立写代码完成了这个功能并通过了测试。在本文不想再赘言。
第二件事情,要想完成它,需了解elf结构,需知道如何把数据从内存A位置复制到内存B位置,也就是说,需要实现一个函数,memcpy(int dest, int off, int size)。三个参数分别是:在内存中的虚拟地址、程序段在文件中的偏移量、程序段的长度。三个参数都能从ELF文件的elf头和程序头中获取。
参照位置是elf文件的开头。偏移量28个字节的内存位置,给它起个标记叫P,从P开始的若干个字节(忘记了具体数字)的内存存储的是程序段的偏移量。文件开头加上这个偏移量,是第一个程序头的内存初始位置。
程序头也存储在一片内存中。用C语言中的struct帮助描述。程序头是一个struct结构,成员变量有程序段的长度、程序段的偏移量、程序段在内存中的虚拟位置(也就是这个程序段将要被重新放置在内存中的位置)。这三个成员变量,就是函数memcpy需要的三个参数。
memcpy的实现
memcpy,有三个参数,分别是:数据要被复制到的内存地址dst,数据的原始地址src,数据的长度size。这个函数的功能是,把src处的size个字节的数据复制到dst处,返回值是src。
直接上代码。
mempcy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov esi, [ebp+12] ; src
mov edi, [ebp+8] ; dst
mov ecx, [ebp+16] ; size
.1
cmp ecx, 0
jz .2
mov al, [ds:esi]
mov [es:edi], al
inc esi
inc edi
dec ecx
jmp .1
.2
mov eax, [ebp+8]
pop ecx
pop edi
pop esi
pop ebp
ret
详细解读这个函数的实现。
在汇编中实现一个函数,模板是:
functionName:
; some code
; some code
ret
汇编函数必须用ret结尾。它的作用是在函数执行结束后,返回调用函数的上层代码的下一条指令。
调用函数时,使用栈传递参数给函数。在函数内部,获取参数时,再从栈中获取参数。
mov esi, [ebp+12] ; src
mov edi, [ebp+8] ; dst
mov ecx, [ebp+16] ; size
ebp指向栈的开始位置栈顶,偏离栈顶4个字节的位置存储的是调用函数指令的下一条指令的位置(大概就是这个意思),它是执行 call 指令时入栈的,是函数调用过程中最后一个入栈的数据。在它之前依次是函数的第一个、第二个、第三个参数入栈(在本函数中),相对于栈顶的偏移量依次是8个字节、12个字节、16个字节。
由于上面的代码修改了esi、edi、ecx中的值,需要在修改之前将它们保存起来,在函数结束时再恢复它们原来的值,所以有下面的代码:
push esi
push edi
push ecx
; some code
; some code
pop ecx
pop edi
pop esi
内存的最小单位是字节,本函数也按字节来复制数据,这不是必须的。复制数据使用
mov al, [ds:esi]
mov [es:edi], al
eax存储2个字,4个字节;ax存储1个字,2个字节;al存储1个字节。ds是数据段,es是什么?有多少个字节,就需要重复多少次上面的复制操作。因此,需要一个循环。
.1
cmp ecx, 0
jz .2
mov al, [ds:esi]
mov [es:edi], al
inc esi
inc edi
dec ecx
jmp .1
在汇编中,loop指令能实现循环功能,本函数却并未使用。这是为了规避恐怖的ecx陷阱。使用loop指令时,需ecx配合。在循环过程中,ecx的值会自动减少。当ecx的值是0时,循环结束。陷阱就出现在这里。具体是咋回事,我忘记了。但我遇到过,再加上在函数体中,可能会修改ecx。为了避免种种诡异的问题,本函数一般使用jmp指令,再配合手工递减的ecx来实现循环功能。作者的其他汇编代码都会如此,尽量不使用loop指令。
使用汇编语言实现memcpy的更多相关文章
- 浅谈单片机中C语言与汇编语言的转换
做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议. 单片机设计:基于51单片机的99码表设计 软件环境:Proteus8 ...
- 汇编语言标志位 含义 NV UP EI NG NZ AC PE CY
缩写原意: Overflow of = OV NV [No Overflow] Direction df = DN (decrement) UP (increment) Interrupt if = ...
- ASM:《X86汇编语言-从实模式到保护模式》第15章:任务切换
15章其实应该是和14章相辅相成的(感觉应该是作者觉得14章内容太多了然后切出来了一点).任务切换和14章的某些概念是分不开的. ★PART1:任务门与任务切换的方法 1. 任务管理程序 14章的时候 ...
- 汇编语言标记寄存器标记位_NV UP EI NG NZ AC PE CY
在8086CPU中,有一种标记寄存器,长度为16bit: 其中存储的信息被称为程序状态字(Program Status Word,PSW),以下将该寄存器简称为flag. 功能:1)用来存储相关指令的 ...
- memcpy内存复制
memcpy(predata,frame,1920*1080*4);
- strcpy strlen memcpy等的函数实现
#include <assert.h> #include <string.h> #include <stdlib.h> #include <stdio.h&g ...
- memcpy函数用法
memcpy函数用法 .分类: VC++ VC++ mfc matlab 2011-12-01 19:17 14538人阅读 评论(0) 收藏 举报 null 原型:extern void *memc ...
- 汇编语言学习与Makefile入门
继续开发 ; hello-os ; TAB= ORG 0x7c00 ; 指明程序的装载地址 ; 以下的记述用于标准FAT12格式的软盘 JMP entry DB 0x90 DB "HELLO ...
- memcpy和memmove
memcpy函数 函数原型 void *memcpy(void *dest, const void *src, size_t n); dest:目标地址 src: 起始地址 n: 字节数 头文件 st ...
随机推荐
- python实现域名注册查询
author:摘繁华-蓝白社区 联合出品 域名生成与查询 文件说明: [x] .py源文件 [x] .exe可执行文件 [x] .config.json配置文件 ps: .exe和config.jso ...
- C#扫盲篇(一):反射机制--情真意切的说
在一线编码已有多年,积累了不少非常实用的技能,最近的更新会逐步的分享出来,希望能帮助到还有一丢丢喜欢.Net的朋友,当然这些都比较适合入门选手,虽然自己已是个精通抄代码的老猿,但技术造诣仍是渣渣. 犹 ...
- 结合MATLAB、Python、R语言,在求得显著差异的边(节点对)之后,怎么画circle图
先来看看成果图: OK,开始画图: 实验背景声明:在脑影像分析中,我们首先构建脑网络,然 ...
- 万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题…..
1.类加载过程 类加载时机 「加载」 将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存上创建一个java.lang.Class对象用来封装类在方法区内的数据 ...
- 【SpringBoot1.x】SpringBoot1.x 开发热部署和监控管理
SpringBoot1.x 开发热部署和监控管理 热部署 在开发中我们修改一个 Java 文件后想看到效果不得不重启应用,这导致大量时间花费,我们希望不重启应用的情况下,程序可以自动部署(热部署). ...
- 【JavaWeb】AJAX 请求
AJAX 请求 什么是 AJAX AJAX(Asynchronous JavaScript And XMl),即异步 JS 和 XML.是指一种创建交互式网页应用的网页开发技术. AJAX 是一种浏览 ...
- MongoDB Sharding(一) -- 分片的概念
(一)分片的由来随着系统的业务量越来越大,业务系统往往会出现这样一些特点: 高吞吐量 高并发 超大规模的数据量 高并发的业务可能会耗尽服务器的CPU,高吞吐量.超大规模的数据量也会带来内存.磁盘的压力 ...
- Docker学习笔记之使用Docker数据卷
Docker数据卷将数据存储到主机而非容器,多个容器需要共享数据时,常常使用数据卷. 1. 为容器设置数据卷(不指定主机目录) 2. 容器与主机之间.容器与容器之间共享数据卷(指定主机目录) 3. 使 ...
- mysql中更改字段属性实际上都做了哪些操作
mysql> set profiling=1; Query OK, 0 rows affected (0.00 sec) mysql> alter table test modify n ...
- ping 命令示例
将下面的代码粘贴到记事本中,然后保存为扩展名为BAT的文件,运行就可以将网段内ping不通的IP地址写入到文本文件IP.txt中. @echo offsetlocal ENABLEDELAYEDEXP ...