所以今天早上我发布了一个关于汇编的疑问,我收到了一些非常真实的帮助,我非常感谢。
现在我开始进入集会,并开始了解它是如何运作的。
我觉得我理解的东西包括堆栈,中断,二进制/十六进制,以及一般大多数基本操作(jmp,push,mov等)。
我正在努力理解并希望获得帮助的概念如下 - 如果您能解决以下任何问题,那将是一个巨大的帮助:
一些信息:我使用masm32和WinAsm作为IDE,我正在使用Windows 7.我有很多以前使用c ++ / java等高级语言编程的经验。
编辑:感谢大家的帮助,照常提供非常丰富的信息!好东西!最后一件事 - 我想知道堆栈指针和Base指针,ESP和EBP之间有什么区别。有人可以帮助我吗?
编辑:我想我现在得到它...... ESP总是指向堆栈顶部。但是,您可以根据需要指定EBP。 ESP会自动处理,但您可以使用EBP做任何您想做的事情。例如:
push 6
push 5
push 4
mov EBP, ESP
push 3
push 2
在这种情况下,EBP现在指向持有4的地址,但ESP现在指向持有2的地址。
在实际应用程序中,6,5和4可能是函数参数,而3和2可能是该函数中的局部变量。
答案 0 :(得分:32)
让我们尝试按顺序回答!
数据部分包含系统在调用程序入口点之前要为您自动初始化的所有内容。你是对的,通常全局变量在这里结束。零初始化数据通常不包含在可执行文件中,因为没有理由 - 程序加载器的几个指令都是生成该空间所需的全部内容。程序开始运行后,ZI和数据区域通常可以互换。 Wikipedia提供了更多信息。
在汇编编程时,变量并不存在,至少在你编写C代码时并不是这样。你所拥有的只是你对如何记忆的决定。变量可以在堆栈中,内存中的某个位置,也可以只存在于寄存器中。
寄存器是处理器的内部数据存储器。通常,您只能对处理器寄存器中的值执行操作。您可以在内存中加载和存储内容,这是计算机工作方式的基本操作。这是一个简单的例子。这个C代码:
int a = 5;
int b = 6;
int *d = (int *)0x12345678; // assume 0x12345678 is a valid memory pointer
*d = a + b;
可能会按照以下方式转换为某些(简化的)程序集。
load r1, 5
load r2, 6
load r4, 0x1234568
add r3, r1, r2
store r4, r3
在这种情况下,您可以将寄存器视为变量,但通常情况下,任何一个变量都不必始终保持在同一个寄存器中;根据您的日常工作的复杂程度,甚至可能无法实现。您需要将一些数据压入堆栈,关闭其他数据,依此类推。 “变量”是逻辑数据,而不是它存在于内存或寄存器中的位置等。
数组只是一个连续的内存块 - 对于本地数组,您可以恰当地减少堆栈指针。对于全局数组,您可以在数据部分中声明该块。
有许多关于寄存器的约定 - 检查平台的ABI或调用约定文档以获取有关如何正确使用它们的详细信息。您的汇编程序文档也可能包含信息。查看ABI article on wikipedia。
您的汇编程序可以对任何C程序进行相同的系统调用,因此您只需调用malloc()
即可从堆中获取内存。
答案 1 :(得分:17)
我想补充一点。计算机上的程序通常分为三个部分,但还有其他部分。
代码段 - .code,。text:http://en.wikipedia.org/wiki/Code_segment
在计算中,也是代码段 称为文本段或简称为 text,是用来指代a的短语 内存或目标文件的一部分 包含可执行指令。 它有固定的大小,通常是 只读。如果文本部分不是 只读,然后是特定的 架构允许自我修改 码。如果,只读代码是可重入的 它可以由多个人执行 过程同时进行。作为记忆 区域,代码段驻留在 内存的下半部分或其内部 在底部,为了防止堆积 堆栈溢出来覆盖它。
数据细分 - .data:http://en.wikipedia.org/wiki/Data_segment
数据段是其中一个部分 目标文件中的程序或 内存,包含全局 变量和静态变量 由程序员初始化。它 有一个固定的大小,因为所有的 本节中的数据由 程序员在程序之前 加载。但是,它不是只读的, 因为变量的值可以 在运行时被改变。这是在 与Rodata形成对比(不变, 只读数据)部分,以及 代码段(也称为文本 段)。
BSS:http://en.wikipedia.org/wiki/.bss
在计算机编程中,.bss或bss (最初代表Block 由Symbol开始)被许多人使用 编译器和链接器作为一个名称 包含的数据段的一部分 静态变量和全局变量 完全填充的 最初的零值数据(即, 执行开始时)。经常这样 被称为“bss部分”或 “bss段”。程序加载器 初始化分配的内存 加载时的bss部分 程序
如其他人所述,寄存器是CPU存储数据或存储器地址的工具。操作是在寄存器上执行的,例如add eax, ebx
并且取决于汇编方言,这意味着不同的事情。在这种情况下,这转换为将ebx的内容添加到eax并将其存储在eax(NASM语法)中。 GNU AS(AT& T)中的等价物是:movl $ebx, $eax
。不同的组装方言有不同的规则和操作符。由于这个原因,我不是MASM的粉丝 - 它与NASM,YASM和GNU AS都截然不同。
实际上没有与C. ABI的一般交互指定如何发生这种情况;例如,在x86(unix)上你会发现一个方法的参数被压入堆栈,而在Unix上的x86-64中,前几个参数将被放置在寄存器中。两个ABI都希望函数的结果存储在eax / rax寄存器中。
这是一个32位的添加例程,可以为Windows和Linux组装。
_Add
push ebp ; create stack frame
mov ebp, esp
mov eax, [ebp+8] ; grab the first argument
mov ecx, [ebp+12] ; grab the second argument
add eax, ecx ; sum the arguments
pop ebp ; restore the base pointer
ret
在这里,你可以看到我的意思。 “返回”值在eax中找到。相比之下,x64版本看起来像这样:
_Add
push rbp ; create stack frame
mov rbp, rsp
mov eax, edi ; grab the first argument
mov ecx, esi ; grab the second argument
add eax, ecx ; sum the arguments
pop rbp ; restore the base pointer
ret
有些文件定义了这种事情。这是UNIX x64 ABI:http://www.x86-64.org/documentation/abi-0.99.pdf。我相信你可能会找到你需要的任何处理器,平台等的ABI。
如何在装配中操作阵列?指针算术。给定eax
处的基址,如果整数大小为4个字节,则下一个存储的整数将为[eax+4]
。您可以使用malloc / calloc调用创建此空间,或者调用内存分配系统调用,无论您的系统是什么。
什么是'堆'?再次根据维基百科,它是为动态内存分配保留的内存区域。在调用calloc,malloc或内存分配系统调用之前,您在汇编程序中看不到它,但它就在那里。
对于这篇文章感到抱歉。