
NASM属于当下极为流行的开源汇编器当中的一个, 不少人于学习底层编程之时会碰到它, 或者在学习逆向工程时也会遇到它, 它具备的核心能力, 乃是将人类易于读懂的汇编指令转变成计算机能够执行的机器码, 这个过程看上去好像挺简单, 然而其背后是包括指令编码、段定义以及输出格式等方面的细节, 这篇文章会依据实际应用为出发点, 讲述NASM在这条转换链里究竟充当什么角色。汇编代码怎么变成机器码的NASM的工作流程事实上挺笔直。你撰写一段汇编源码, 像mov eax, 1这样, NASM会依照Intel的指令格式, 将其转化成对应的字节序列。就像上面这条指令, 在32位模式下或许会被编码成B8 01 00 00 00。这里存在一个关键要点: 不同的指令前缀、操作数大小、寻址方式都会对最终机器码的长度以及结构产生影响。于实际项目当中, 不少人会径直利用NASM编译产出二进制文件, 而后借助hexdump或者调试器去查看机器码。举例而言, 如果撰写一个简易的引导扇区程序, NASM在配合-f bin格式时能够直接输出纯二进制, 且无需任何链接器予以介入。此时机器码的每一个字节均可对应至CPU的原始指令, 极为契合用于学习或者制作小型系统。在逆向工程的那种场景状况之下, NASM居然还能够将机器码给反汇编回转过来。虽说它主要是作为一个汇编器存在, 可是借助ndisasm工具, 你能够把一段十六进制的数据转变成为汇编指令。这对于去分析恶意软件或者理解编译器所生成的代码而言是极为实用的。就好比你从内存之中dump出一段shellcode, 运用NASM对其进行反汇编操作, 便能够清晰地看到它调用了哪些系统调用。不同输出格式对转换有什么影响NASM支持好些种输出格式, 像那个 -f elf是用于Linux目标文件的, -f win32是用于Windows的, -f bin是用于纯二进制的。这些格式直接就决定了机器码的布局以及元数据。比如说, 要是你用 -f elf进行编译, 那输出的.o文件当中, 除了机器码之外, 还包含着符号表、重定位信息等等。并且要是采用 -f bin, NASM便只会依照你所设定的段定义次序, 将指令以及数据原封不动地书写进去。该种差异于实际工作里极为重要, 倘若你在撰写一个内核模块, 且需与C代码进行链接, 那么就得运用-f elf64, 以使NASM生成契合ELF规范的目标文件, 要是你仅仅想将一段代码固化至ROM之中, 运用-f bin会更为直接, 这是由于无需处理链接器的符号解析问题。除此之外, NASM的伪指令同样会对机器码的生成造成影响, 比如说org指令能够指定代码加载的起始地址, 而这个地址会直接参与到跳转指令的机器码计算当中, 举例来讲, 在引导扇区里, 倘若你设置org 0x7C00, 那么NASM就会依据这个地址去计算跳转偏移, 如此一来最终生成的机器码才能够正确跳转。