到目前为止,我一直在学习编写一些 x86_64 程序集。我读到可以减去 RSP 来向下增长堆栈并分配空间,所以我编写了以下代码:
push %rbp
movq %rsp, %rbp
subq $16, %rsp
movq $200, -8(%rsp)
movq $300, -16(%rsp)
popq %rbp
retq
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这将创建一个函数,在其中设置堆栈帧,然后在堆栈上分配 16 个字节,并将 -8 和 -16 的值分别设置为 200 和 300。但是,当我使用 gcc 运行此程序时,出现分段错误。不过,如果我删除sub程序的一部分,它就可以完美运行。我想我误解了一些东西,那么这里到底发生了什么?
我正在使用从汇编代码组装的多个目标文件来制作可重定位共享库(所有编译都应使用 -fPIC 和 -DPIC)。
在我的代码中我有push label说明。当我使用一切看起来都很好将汇编代码组装成目标文件时-fPIC -DPIC,但是当我想使用目标文件创建共享库时,我收到了消息relocation R_X86_64_32S against '.text' can not be used when making a shared object; recompile with -fPIC。
我确信问题出在这些push label说明上,因为当我删除它们时,错误就会消失。
关于如何组装它有什么想法吗?
顺便说一句,我的平台是采用 Intel x86_64 架构的 Linux,编译器gcc采用 GAS 语法。我对 64 位库感兴趣。
我正在查看radare2 中的一些测试代码,但我无法理解反汇编程序如何确定调用指令如何跳转到的位置。考虑一下:
在 0x00001090 处,puts() 被调用。我想自己解析与该指令相关的二进制文件 (e89bffffff),因此我通过 lib capstone 运行它并得到了以下结果:
所以我们可以看到实际的操作数是0xfb0。然后在 rasm2 中我们有:
# rasm2 -a x86 -b 64 -d e8a1ffffff
call 0xffffffffffffffa6
Run Code Online (Sandbox Code Playgroud)
这是不同的。我预计 libcapstone 和 rasm2 具有相同的输出。
我的主要问题是,如何解释 0xfb0 (或 0xffffffffffffffa6)来获取下一条指令地址?就我而言,根据雷达,sym.imp.puts 位于 0x00001030。
L2是非排除性的,这是一个有据可查的事实,这意味着 L2 不必包含 L1DCache 拥有的所有行。
\n\nL1d miss (Read, RFO) 是否也错过了 L2 填充 L1d 行而不填充相应的 L2 行?英特尔 mans 中有对此有任何解释吗?更新:有。Intel Vol.3,有关内存类型的部分。
\n\n或者用另一种方式重新表述这个问题:缺少 L2 的查找是否总是会导致其行被填充?
\n\n经过一番挖掘后,我自己发现了答案。它是回写内存类型的属性,而不是缓存级别
\n\n\n\n回写 (WB) \xe2\x80\x94 对系统内存的写入和读取均被缓存。读取来自缓存命中时的缓存行;读取未命中导致\n 缓存已满。
\n
我正在检查 Ericksons Hacking: The Art of Exploitation 中的这段代码片段:
\nvoid test_function(int a, int b, int c, int d) {\n int flag;\n char buffer[10];\n flag = 31337;\n buffer[0] = \'A\';\n}\n\nint main() {\n test_function(1, 2, 3, 4); \n}\nRun Code Online (Sandbox Code Playgroud)\nvoid test_function(int a, int b, int c, int d) {\n int flag;\n char buffer[10];\n flag = 31337;\n buffer[0] = \'A\';\n}\n\nint main() {\n test_function(1, 2, 3, 4); \n}\nRun Code Online (Sandbox Code Playgroud)\n我在 main 和 test_function 处设置了断点。\n当中断 main 时,我得到以下输出:
\ngcc -g stack_example.c\n\ngdb -q ./a.out\n\ngef\xe2\x9e\xa4list main\n\n\n 0x555555555192 …Run Code Online (Sandbox Code Playgroud) 我是汇编新手,从我了解到的情况.code与 相同.text,但下面的代码将使用.code.
segment .data
msg db "hello, world", 0xa
len equ $ - msg
section .text
global _start
_start:
mov edx, len
mov ecx, msg
mov ebx, 1
mov eax, 4
int 0x80
mov ebx, 0
mov eax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
nasm -f elf64 -o hello.o hello.s
ld -s -o hello hello.o
hello, world
sed -i s/.text/.code/ ./hello.s
nasm -f elf64 -o hello.o hello.s
ld -s -o hello hello.o
./stack.sh: line 8: 4621 Segmentation …Run Code Online (Sandbox Code Playgroud) 我用 C 语言编写了一个非常简单的函数,它使用strlen()from<string.h>返回变量的长度char*:
int length(char *str) {
return strlen(str);
}
Run Code Online (Sandbox Code Playgroud)
以下是相应的 x86_64 程序集objdump -M intel -d a.out:
00000000000011a8 <length>:
11a8: f3 0f 1e fa endbr64
11ac: 55 push rbp
11ad: 48 89 e5 mov rbp,rsp
11b0: 48 83 ec 10 sub rsp,0x10
11b4: 48 89 7d f8 mov QWORD PTR [rbp-0x8],rdi
11b8: 48 8b 45 f8 mov rax,QWORD PTR [rbp-0x8]
11bc: 48 89 c7 mov rdi,rax
11bf: e8 ac fe ff ff …Run Code Online (Sandbox Code Playgroud) 在这个简单的函数中,为局部变量分配了空间。然后,变量被初始化并被printf调用以输出它们。
000000000040056a <func>:
40056a: 55 push rbp ; function prologue
40056b: 48 89 e5 mov rbp,rsp ; function prologue
40056e: 48 83 ec 10 sub rsp,0x10 ; deallocating space for local variables
400572: 8b 4d fc mov ecx,DWORD PTR [rbp-0x4] ; variable initialization
400575: 8b 55 f8 mov edx,DWORD PTR [rbp-0x8] ; variable initialization
400578: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc] ; variable initialization
40057b: 89 c6 mov esi,eax ; string stuff
40057d: bf 34 06 40 …Run Code Online (Sandbox Code Playgroud) 我正在用 c 语言编写一个国际象棋引擎,速度至关重要。国际象棋引擎基于 unsigned long long,我将其表示为 u64,并且它严重依赖于最低有效位扫描。到目前为止,我一直在使用 gcc 函数 __builtin_ctzll ,它做得很好。然而,我使用 gcc -S -O2 为这个独立函数生成了汇编代码。它给了我以下内容:
xorl %eax, %eax
rep bsfq %rdi, %rax
cltq
ret
Run Code Online (Sandbox Code Playgroud)
然而经过一番调查似乎代码
rep bsfq %rdi, %rax
ret
Run Code Online (Sandbox Code Playgroud)
在我的国际象棋程序中做了完全相同的事情。然而现在速度慢了约 20%。它应该更快,因为它的指令更少。然而,原始的 __builtin_ctzll 内联在我的 C 代码中。这是我的自定义汇编代码运行速度比原始代码慢的原因吗?因为当我声明函数 ctzll 时,我当然不能在 c 中内联声明它,除非我有定义(不在汇编代码中)。
是否有另一种方法来优化汇编指令,或者我应该尝试直接在 c 中内联 asm 的新汇编代码?
在我的 FASM 项目(对象)中,我尝试创建一个跳转表并用于dq每个跳转地址,但有一个问题!
对于每个dq .jmp1(跳转地址定义),.jmp1我的最终 .o 文件的总大小将添加 24 个字节(加上地址的 8 个字节(总共 32 个字节))!
那额外的 24 个字节是什么?有什么办法可以避免吗?这种情况仅发生在目标文件中,而不发生在可执行文件中!
它定义了 32 个字节,而不是每个跳转地址 8 个字节!问题是什么?
format ELF64
section '.text'
func:
lea rax, [8*rax+.jmp_table]
.jmp1:
.jmp_table:
dq .jmp1 ; 8 bytes + 24 bytes !!! (to .o total size)
dq .jmp1 ; 8 bytes + 24 bytes !!! (to .o total size)
Run Code Online (Sandbox Code Playgroud)
但是当我创建一个可执行文件时,每个文件dq只需要 8 个字节(这是我所期望的)......
format ELF64 EXECUTABLE
segment readable executable
func:
lea rax, [8*rax+.jmp_table]
.jmp1:
.jmp_table: …Run Code Online (Sandbox Code Playgroud) assembly ×10
x86-64 ×10
c ×3
x86 ×3
cpu-cache ×1
elf ×1
executable ×1
fasm ×1
gcc ×1
nasm ×1
object-files ×1
stack-frame ×1