以下所有说明都做同样的事情:设置%eax为零.哪种方式最佳(需要最少的机器周期)?
xorl %eax, %eax
mov $0, %eax
andl $0, %eax
Run Code Online (Sandbox Code Playgroud) 我正在用这个把我的头撞到墙上。
在我的项目中,使用mmap映射(/proc/self/maps)分配内存时,尽管我只请求了可读内存,但它仍是一个可读且可执行的区域。
在研究了strace(看起来不错)和其他调试之后,我能够确定似乎唯一可以避免这个奇怪问题的东西:从项目中删除程序集文件,只保留纯C。(什么?!)
所以这是我一个奇怪的例子,我正在使用Ubunbtu 19.04和默认的gcc。
如果使用ASM文件(为空)编译目标可执行文件,则将mmap返回一个可读和可执行区域,如果构建时没有该区域,则它将正常运行。请参阅/proc/self/maps示例中已嵌入的输出。
example.c
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main()
{
void* p;
p = mmap(NULL, 8192,PROT_READ,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);
{
FILE *f;
char line[512], s_search[17];
snprintf(s_search,16,"%lx",(long)p);
f = fopen("/proc/self/maps","r");
while (fgets(line,512,f))
{
if (strstr(line,s_search)) fputs(line,stderr);
}
fclose(f);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
example.s:是一个空文件!
产出
附带ASM版本
VirtualBox:~/mechanics/build$ gcc example.c example.s -o example && ./example
7f78d6e08000-7f78d6e0a000 r-xp 00000000 00:00 0
Run Code Online (Sandbox Code Playgroud)
没有ASM随附的版本
VirtualBox:~/mechanics/build$ gcc example.c -o example && ./example
7f1569296000-7f1569298000 …Run Code Online (Sandbox Code Playgroud) 来自wiki 可执行文件和可链接格式:
这些段包含运行时执行文件所必需的信息,而段包含用于链接和重定位的重要数据.整个文件中的任何字节最多只能由一个部分拥有,并且可能存在不属于任何部分的孤立字节.
但是段和段之间有什么区别?在可执行的ELF文件中,段是否包含一个或多个部分?
我正在为最近一直在研究的业余爱好虚拟机编写JIT编译器.我知道有点汇编,(我主要是一个C程序员.我可以阅读大多数汇编参考我不理解的操作码,并编写一些简单的程序.)但我很难理解这几个例子我在网上找到的自修改代码.
这是一个这样的例子:http://asm.sourceforge.net/articles/smc.html
提供的示例程序在运行时进行了大约四种不同的修改,其中没有一个被清楚地解释.Linux内核中断被多次使用,没有解释或详细说明.(作者在调用中断之前将数据移动到几个寄存器中.我假设他正在传递参数,但这些参数根本没有解释,让读者猜测.)
我正在寻找的是自修改程序代码中最简单,最直接的例子.我可以看到的东西,用于理解如何编写x86程序集中的自修改代码,以及它是如何工作的.您是否有任何资源可以指向我,或者您可以提供的任何示例都能充分证明这一点?
我正在使用NASM作为我的汇编程序.
编辑:我也在Linux上运行此代码.
我想为我编写的玩具语言处理器编写一个非常小的概念验证JIT编译器(纯粹是学术性的),但我在设计的中间高度上遇到了一些麻烦.从概念上讲,我熟悉JIT的工作原理 - 您将字节码编译成(机器或汇编?)代码来运行.然而,在螺栓和螺栓水平上,我并不是在想你实际上是怎么做的.
我的(非常"新手")下意识的反应,因为我没有第一个线索从哪里开始,将尝试类似以下内容:
这甚至接近正确的算法吗?我已经尝试过阅读我知道有JIT编译器学习的不同项目(比如V8),但是由于它们的大小,这些代码库很难被消费,而我几乎不知道从哪里开始寻找.
考虑使用C程序(请参阅此处的实时演示).
const int main = 195;
Run Code Online (Sandbox Code Playgroud)
我知道在现实世界中没有程序员编写这样的代码,因为它没有任何用处,也没有任何意义.但是当我const从程序上方删除关键字时,它会立即导致分段错误.为什么?我很想知道这背后的原因.
GCC 4.8.2在编译时会发出以下警告.
警告:'main'通常是一个函数[-Wmain]
Run Code Online (Sandbox Code Playgroud)const int main = 195; ^
为什么const关键字的存在和缺失会对程序的行为产生影响?
我被告知并且从英特尔的手册中读到可以将指令写入内存,但是指令预取队列已经获取了陈旧的指令并将执行那些旧的指令.我没有成功观察到这种行为.我的方法如下.
英特尔软件开发手册从第11.6节开始说明
对当前在处理器中高速缓存的代码段中的存储器位置的写入导致相关联的高速缓存行(或多个行)无效.此检查基于指令的物理地址.此外,P6系列和奔腾处理器检查对代码段的写入是否可以修改已经预取执行的指令.如果写入影响预取指令,则预取队列无效.后一种检查基于指令的线性地址.
所以,看起来如果我希望执行陈旧的指令,我需要有两个不同的线性地址引用相同的物理页面.所以,我将内存映射到两个不同的地址.
int fd = open("code_area", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd>=0);
write(fd, zeros, 0x1000);
uint8_t *a1 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FILE | MAP_SHARED, fd, 0);
uint8_t *a2 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FILE | MAP_SHARED, fd, 0);
assert(a1 != a2);
Run Code Online (Sandbox Code Playgroud)
我有一个汇编函数,它接受一个参数,一个指向我想要更改的指令的指针.
fun:
push %rbp
mov %rsp, %rbp
xorq %rax, %rax # Return value 0
# A far jump simulated with a far return
# Push the …Run Code Online (Sandbox Code Playgroud) 我不小心在该.data部分中编写了我的汇编代码。我编译并执行了它。该程序在Linux下正常运行5.4.0-53-generic,即使我没有指定就像一面旗帜execstack。
之后,我在 Linux 下执行了该程序5.9.0-050900rc5-generic。该程序得到了SIGSEGV。我通过阅读检查了虚拟内存权限/proc/$pid/maps。事实证明,该部分不可执行。
我认为 Linux 上有一个配置可以管理该权限。但我不知道在哪里可以找到。
ammarfaizi2@integral:/tmp$ uname -r
5.4.0-53-generic
ammarfaizi2@integral:/tmp$ cat test.asm
[section .data]
global _start
_start:
mov eax, 60
xor edi, edi
syscall
ammarfaizi2@integral:/tmp$ nasm --version
NASM version 2.14.02
ammarfaizi2@integral:/tmp$ nasm -felf64 test.asm -o test.o
ammarfaizi2@integral:/tmp$ ld test.o -o test
ammarfaizi2@integral:/tmp$ ./test
ammarfaizi2@integral:/tmp$ echo $?
0
ammarfaizi2@integral:/tmp$ md5sum test
7ffff5fd44e6ff0a278e881732fba525 test
ammarfaizi2@integral:/tmp$
Run Code Online (Sandbox Code Playgroud)
## Debug
gef? shell …Run Code Online (Sandbox Code Playgroud) 对于大学课程,我喜欢比较使用 gcc/clang 与汇编编写和编译的功能相似程序的代码大小。在重新评估如何进一步缩小某些可执行文件的大小的过程中,当我 2 年前组装/链接的完全相同的汇编代码在重新构建后现在已经增长了 10 倍以上时,我简直不敢相信自己的眼睛适用于多个程序,不仅是 helloworld):
$ make
as -32 -o helloworld-asm-2020.o helloworld-asm-2020.s
ld -melf_i386 -o helloworld-asm-2020 helloworld-asm-2020.o
$ ls -l
-rwxr-xr-x 1 xxx users 708 Jul 18 2018 helloworld-asm-2018*
-rwxr-xr-x 1 xxx users 8704 Nov 25 15:00 helloworld-asm-2020*
-rwxr-xr-x 1 xxx users 4724 Nov 25 15:00 helloworld-asm-2020-n*
-rwxr-xr-x 1 xxx users 4228 Nov 25 15:00 helloworld-asm-2020-n-sstripped*
-rwxr-xr-x 1 xxx users 604 Nov 25 15:00 helloworld-asm-2020.o*
-rw-r--r-- 1 xxx users 498 Nov 25 14:44 helloworld-asm-2020.s
Run Code Online (Sandbox Code Playgroud)
汇编代码是:
.code32
.section …Run Code Online (Sandbox Code Playgroud) 需要创建一个脚本来检查内核是否处于PAE模式.当然,仅检查/ proc/cpuinfo标志是否具有此"pae"设置是不够的.
我们必须知道PAE机制是否实际上不仅实现了,而且还被激活.
因为PAE内核现在是新的默认值,如果你需要一个非PAE内核,那么现在必须创建另一个内核.
换句话说,我们如何判断内核在具有PAE的CPU上是否是非PAE(是测试的两个可能条件之一).
另一个是,如何在没有PAE支持的CPU上判断内核是否为PAE.
并且没有办法判断在典型的安全内核中是否使用了CONFIG_HIGHMEM或CONFIG_PAE内核配置选项.
memory kernel memory-management cpu-architecture linux-kernel