Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 这个汇编语言代码是什么意思?_Assembly_X86 - Fatal编程技术网

Assembly 这个汇编语言代码是什么意思?

Assembly 这个汇编语言代码是什么意思?,assembly,x86,Assembly,X86,我是一名学生,刚开始学习汇编语言。为了更好地理解它,我用C写了一篇短文,并将其转换成汇编语言。令人惊讶的是,我一点也不懂 代码是: #包括 int main() { int n; n=4; printf(“%d”,n); 返回0; } 相应的汇编语言为: .file "delta.c" .section .rodata .LC0: .string "%d" .text .globl main .type main, @function m

我是一名学生,刚开始学习汇编语言。为了更好地理解它,我用C写了一篇短文,并将其转换成汇编语言。令人惊讶的是,我一点也不懂

代码是:

#包括
int main()
{
int n;
n=4;
printf(“%d”,n);
返回0;
}
相应的汇编语言为:

.file   "delta.c"
    .section    .rodata
.LC0:
    .string "%d"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $4, 28(%esp)
    movl    $.LC0, %eax
    movl    28(%esp), %edx
    movl    %edx, 4(%esp)
    movl    %eax, (%esp)
    call    printf
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits
这些是什么意思?

让我们把它分解一下:

.file   "delta.c"
编译器正在使用它来告诉您程序集来自的源文件。这对汇编程序没有多大意义

.section    .rodata
这将开始一个新的部分。“rodata”是“只读数据”部分的名称。本节最后将数据写入可执行文件,该可执行文件将内存映射为只读数据。一个可执行映像的所有“.rodata”页面最终都会被所有创建该映像的进程共享 加载图像

通常,源代码中任何无法优化为程序集内部函数的“编译时常量”最终都会存储在“只读数据段”中

.LC0“
部分是一个标签。它提供一个符号名,用于引用文件中其后出现的“是”。在本例中,“LC0”表示字符串“%d”。GNU汇编程序使用以“L”开头的标签被视为“本地标签”的约定“。这有一个技术意义,对编写编译器和链接器的人来说最有趣。在本例中,编译器使用它来引用特定对象文件专用的符号。在本例中,它表示一个字符串常量

.text
这将开始一个新的部分。“文本”部分是对象文件中存储可执行代码的部分

.globl  main
“.global”指令告诉汇编程序将其后面的标签添加到由生成的对象文件“导出”的标签列表中。这基本上意味着“这是一个链接器应该可见的符号”。例如,“C”中的“非静态”函数可以由声明(或包含)兼容函数原型的任何C文件调用。这就是为什么您可以
#包括stdio.h
,然后调用
printf
。编译任何非静态C函数时,编译器将生成声明指向函数开头的全局标签的程序集。将此与不应链接的内容(如字符串文字)进行对比。对象文件中的程序集代码仍然需要一个标签来引用文本数据。这些是“本地”符号

.type   main, @function
我不确定GAS(gnu汇编程序)如何处理“.type”指令。但是,这会指示汇编程序标签“main”是指可执行代码,而不是数据

main:
这定义了“main”函数的入口点

.LFB0:
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $4, 28(%esp)
这是一个“本地标签”,表示函数的开始

    .cfi_startproc
这是一个“调用帧信息”指令。它指示汇编程序发出dwarf格式调试信息

    pushl   %ebp
    movl    %esp, %ebp
这是汇编代码中函数“序言”的标准部分。它正在保存“ebp”寄存器的当前值。“ebp”或“base”寄存器用于在函数中存储堆栈帧的“base”。虽然“esp”(“堆栈指针”)寄存器可以随着函数内调用函数而更改,“ebp”保持不变。函数的任何参数始终可以相对于“ebp”进行访问。根据ABI调用约定,在函数修改EBP寄存器之前,必须先保存它,以便在函数返回之前恢复原始值

    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
我没有详细研究过这些,但我相信它们与DWARF调试信息有关

    pushl   %ebp
    movl    %esp, %ebp
GAS使用AT&T语法,这与英特尔手册使用的语法相反。这意味着“将ebp设置为等于esp”。这基本上为函数的其余部分建立了“基指针”

.LFB0:
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $4, 28(%esp)
这也是该功能的外百叶窗的一部分。这将对齐堆栈指针,然后从中减去足够的空间来容纳函数的所有局部变量

.LFB0:
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    movl    $4, 28(%esp)
这会将32位整数常量4加载到堆栈帧中的插槽中

    movl    $.LC0, %eax
这会将上面定义的“%d”字符串常量加载到eax中

    movl    28(%esp), %edx
这会将存储在堆栈偏移量28中的值“4”加载到edx。您的代码可能是在关闭优化的情况下编译的

    movl    %edx, 4(%esp)
然后将值4移动到堆栈中调用printf时需要的位置

    movl    %eax, (%esp)
    call    printf
这会将字符串“%d”加载到调用printf时堆栈上需要的位置

    movl    %eax, (%esp)
    call    printf
这就叫printf

    movl    $0, %eax
这将eax设置为0。假设下一条指令是“leave”和“ret”,这相当于C代码中的“return0”。EAX寄存器用于保存函数的返回值

    leave
此指令清除调用帧。它将ESP设置回EBP,然后将EBP从修改后的堆栈指针中弹出。与下一条指令一样,这也是函数结尾的一部分

    .cfi_restore 5
    .cfi_def_cfa 4, 4
这更像是矮人的东西

    ret
这是实际返回指令。它从函数返回

    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
    .section    .note.GNU-stack,"",@progbits

对我来说,intels语法更容易阅读,学习如何生成intels语法对于更好地理解C程序很方便

gcc -S -masm=intel file.c
在windows中,您的C程序变成

    .file   "file.c"
    .intel_syntax noprefix
    .def    ___main;    .scl    2;  .type   32; .endef
    .section .rdata,"dr"
LC0:
    .ascii "%d\0"
    .text
    .globl  _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
LFB13:
    .cfi_startproc
    push    ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    mov ebp, esp
    .cfi_def_cfa_register 5
    and esp, -16
    sub esp, 32
    call    ___main
    mov DWORD PTR [esp+28], 4
    mov eax, DWORD PTR [esp+28]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf
    mov eax, 0
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE13:
    .ident  "GCC: (rev2, Built by MinGW-builds project) 4.8.1"
    .def    _printf;    .scl    2;  .type   32; .endef
(ubuntu上的编译器选项应与windows中的相同)

除了精神病的标签,这更像是我在教科书中读到的集会

这是一种看待它的方式

    call    ___main

    mov DWORD PTR [esp+28], 4  
    mov eax, DWORD PTR [esp+28]              ; int n = 4;

    mov DWORD PTR [esp+4], eax 
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf                          ; printf("%d",n);

    mov eax, 0
    leave                                    ; return 0;

哪一部分给你带来了麻烦?我们不能解释每一行,如果你处于那种水平,你需要从阅读一本书开始,而不是直接跳到一些不可理解的东西上。请告诉我们您理解哪些部分,哪些部分不理解。在逐行解释说明的过程中,您的示例中有一些主要概念可能会丢失。如果您对组装说明了解很少或根本不了解,您应该从基础知识入手,获得一本书或一些在线资料。一旦您熟悉了指令的工作方式,那么管理堆栈这一更大的概念就开始了