汇编 - .data,.code和寄存器......?

Cam*_*Cam 28 assembly low-level masm32

所以今天早上我发布了一个关于汇编的混乱问题,我收到了一些非常真实的帮助,我非常感谢.

现在我开始进入组装,并开始了解它是如何工作的.

我觉得我理解的事情包括堆栈,中断,二进制/十六进制,以及一般大多数基本操作(jmp,push,mov等).

我正在努力理解并希望得到帮助的概念如下:如果您能解决以下任何问题,那将是一个巨大的帮助:

  1. .data部分究竟发生了什么?那些变量我们是在申报吗?
  2. 如果是这样,我们可以稍后在代码部分声明变量吗?如果没有,为什么不呢?如果是这样,那么我们如何以及为什么使用数据部分呢?
  3. 什么是注册?它与变量相比如何?我的意思是我知道这是一个存储一小部分信息的位置......但这对我来说听起来就像一个变量.
  4. 我如何制作阵列?我知道这似乎是随机的,但我很好奇我将如何做这样的事情.
  5. 是否列出了每个寄存器应该用于什么的常见做法?我仍然没有完全理解它们,但是已经注意到有些人说,例如,应该使用某个寄存器来存储程序中的"返回值" - 这些实践是否有全面或至少提供信息的列表?
  6. 我正在学习汇编的原因之一是更好地了解我的高级代码背后发生了什么.考虑到这一点 - 当我用c ++编程时,我经常考虑堆栈和堆.在汇编中我知道堆栈是什么 - 在哪里'堆'?

一些信息:我使用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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,EBP现在指向持有4的地址,但ESP现在指向持有2的地址.

在实际应用中,6,5和4可以是函数参数,而3和2可以是该函数内的局部变量.

Car*_*rum 32

让我们尝试按顺序回答!

  1. 数据部分包含系统在调用程序入口点之前要为您自动初始化的所有内容.你是对的,通常全局变量在这里结束.零初始化数据通常不包含在可执行文件中,因为没有理由 - 程序加载器的几个指令都是生成该空间所需的全部内容.程序开始运行后,ZI和数据区域通常可以互换. 维基百科有更多的信息.

  2. 在汇编编程时,变量并不存在,至少在你编写C代码时它们没有.你所拥有的只是你对如何记忆的决定.变量可以在堆栈中,内存中的某个位置,也可以只存在于寄存器中.

  3. 寄存器是处理器的内部数据存储器.通常,您只能对处理器寄存器中的值执行操作.您可以在内存中加载和存储内容,这是计算机工作方式的基本操作.这是一个简单的例子.这个C代码:

    int a = 5;
    int b = 6;
    int *d = (int *)0x12345678; // assume 0x12345678 is a valid memory pointer
    *d = a + b;
    
    Run Code Online (Sandbox Code Playgroud)

    可能会被转换为一些(简化的)程序集:

    load  r1, 5
    load  r2, 6
    load  r4, 0x1234568
    add   r3, r1, r2
    store r4, r3
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,您可以将寄存器视为变量,但一般情况下,任何一个变量都不必始终保持在同一个寄存器中; 根据您的日常工作的复杂程度,甚至可能无法实现.您需要将一些数据压入堆栈,关闭其他数据,依此类推."变量"是逻辑数据,而不是存储在内存或寄存器中的位置等.

  4. 数组只是一个连续的内存块 - 对于本地数组,您可以恰当地减少堆栈指针.对于全局数组,可以在数据部分中声明该块.

  5. 有许多关于寄存器的约定 - 检查平台的ABI或调用约定文档以获取有关如何正确使用它们的详细信息.您的汇编程序文档也可能包含信息.查看维基百科上ABI文章.

  6. 您的汇编程序可以对任何C程序进行相同的系统调用,因此您只需调用malloc()以从堆中获取内存.

  • 是的,您可以在没有push/pop的情况下从堆栈中读取:您只需要堆栈指针和偏移量.在x86 asm中,堆栈指针包含在esp寄存器中,因此您可以使用esp + offset(实际上,如果您反汇编C应用程序,您将看到此方法用于访问函数调用中的"本地"变量). (2认同)

小智 18

我想补充一点.计算机上的程序通常分为三个部分,但还有其他部分.

代码段 - .code,.text:http://en.wikipedia.org/wiki/Code_segment

在计算中,代码段(也称为文本段或简称为文本)是用于指代包含可执行指令的存储器或目标文件的一部分的短语.它具有固定的大小,通常是只读的.如果文本部分不是只读的,那么特定的体系结构允许自修改代码.如果只读代码可以由多个进程同时执行,则只读代码是可重入的.作为内存区域,代码段位于内存的下半部分或最底部,以防止堆和堆栈溢出覆盖它.

数据段 - .data:http://en.wikipedia.org/wiki/Data_segment

数据段是目标文件或内存中程序的一个部分,它包含由程序员初始化的全局变量和静态变量.它具有固定的大小,因为本节中的所有数据都是由程序员在加载程序之前设置的.但是,它不是只读的,因为变量的值可以在运行时更改.这与Rodata(常量,只读数据)部分以及代码段(也称为文本段)形成对比.

BSS:http://en.wikipedia.org/wiki/.bss

在计算机编程中,许多编译器和链接器使用.bss或bss(最初代表块起始符号)作为包含静态变量和全局变量的数据段的一部分的名称,这些变量仅用零值数据填充最初(即,执行开始时).它通常被称为"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
Run Code Online (Sandbox Code Playgroud)

在这里,你可以看到我的意思."返回"值在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
Run Code Online (Sandbox Code Playgroud)

有文件定义了这种事情.这是UNIX x64 ABI:http://www.x86-64.org/documentation/abi-0.99.pdf.我相信你可能会找到你需要的任何处理器,平台等的ABI.

你如何在装配中操作阵列?指针算术.给定下一个eax存储整数的基址,[eax+4]如果整数大小为4个字节则为.您可以使用malloc/calloc调用创建此空间,或者调用内存分配系统调用,无论您的系统是什么.

什么是'堆'?再次根据维基百科,它是为动态内存分配保留的内存区域.在调用calloc,malloc或内存分配系统调用之前,您在汇编程序中看不到它,但它就在那里.

对不起,请写文章.