当前位置: 首页 > news >正文

网站关键词排名系统共享设计平台

网站关键词排名系统,共享设计平台,奎文营销型网站建设,电子商务网站建设与完整实例Linux 汇编器#xff1a;对比 GAS 和 NASM转自 http://www.ibm.com/developerworks/cn/linux/l-gas-nasm.html#ibm-pcon与其他语言不同#xff0c;汇编语言要求开发人员了解编程所用机器的处理器体系结构。汇编程序不可移植#xff0c;维护和理解常常比较麻烦#xff0c;通…Linux 汇编器对比 GAS 和 NASM转自 http://www.ibm.com/developerworks/cn/linux/l-gas-nasm.html#ibm-pcon与其他语言不同汇编语言要求开发人员了解编程所用机器的处理器体系结构。汇编程序不可移植维护和理解常常比较麻烦通常包含大量代码行。但是在机器上执行的运行时二进制代码在速度和大小方面有优势。对于在 Linux 上进行汇编级编程已经有许多参考资料本文主要讲解语法之间的差异帮助您更轻松地在汇编形式之间进行转换。本文源于我自己试图改进这种转换的尝试。本文使用一系列程序示例。每个程序演示一些特性然后是对语法的讨论和对比。尽管不可能讨论 NASM 和 GAS之间存在的每个差异但是我试图讨论主要方面给进一步研究提供一个基础。那些已经熟悉 NASM 和 GAS的读者也可以在这里找到有用的内容比如宏。本文假设您至少基本了解汇编的术语曾经用符合 Intel® 语法的汇编器编写过程序可能在 Linux 或 Windows 上使用过 NASM。本文并不讲解如何在编辑器中输入代码或者如何进行汇编和链接(但是下面的边栏可以帮助您 快速回忆一下)。您应该熟悉 Linux 操作系统(任何 Linux 发行版都可以我使用的是 Red Hat 和 Slackware)和基本的 GNU 工具比如 gcc 和 ld还应该在 x86 机器上进行编程。现在我描述一下本文讨论的范围。构建示例汇编GASas –o program.o program.sNASMnasm –f elf –o program.o program.asm链接(对于两种汇编器通用)ld –o program program.o在使用外部 C 库时的链接方法ld –-dynamic-linker /lib/ld-linux.so.2 –lc –o program program.o本文讨论NASM 和 GAS 之间的基本语法差异常用的汇编级结构比如变量、循环、标签和宏关于调用外部 C 例程和使用函数的信息汇编助记符差异和使用方法内存寻址方法本文不讨论处理器指令集一种汇编器特有的各种宏形式和其他结构NASM 或 GAS 特有的汇编器指令不常用的特性或者只在一种汇编器中出现的特性更多信息请参考汇编器的官方手册(参见 参考资料中的链接)因为这些手册是最完整的信息源。基本结构清单 1 给出一个非常简单的程序它的作用仅仅是使用退出码 2 退出。这个小程序展示了 NASM 和 GAS 的汇编程序的基本结构。清单 1. 一个使用退出码 2 退出的程序行号NASMGAS001002003004005006007008009010011012013014015016; Text segment beginssection .textglobal _start; Program entry point_start:; Put the code number for system callmov eax, 1; Return valuemov ebx, 2; Call the OSint 80h# Text segment begins.section .text.globl _start# Program entry point_start:# Put the code number for system callmovl $1, %eax/* Return value */movl $2, %ebx# Call the OSint $0x80现在解释一下。NASM 和 GAS 之间最大的差异之一是语法。GAS 使用 ATT 语法这是一种相当老的语法由 GAS 和一些老式汇编器使用NASM 使用 Intel 语法大多数汇编器都支持它包括 TASM 和 MASM。(GAS 的现代版本支持 .intel_syntax指令因此允许在 GAS 中使用 Intel 语法。)下面是从 GAS 手册总结出的一些主要差异ATT 和 Intel 语法采用相反的源和目标操作数次序。例如Intelmov eax, 4ATTmovl $4, %eax在 ATT 语法中中间操作数前面加 $在 Intel 语法中中间操作数不加前缀。例如Intelpush 4ATTpushl $4在 ATT 语法中寄存器操作数前面加 %。在 Intel 语法中它们不加前缀。在 ATT 语法中内存操作数的大小由操作码名称的最后一个字符决定。操作码后缀 b、w和 l分别指定字节(8 位)、字(16 位)和长(32 位)内存引用。Intel 语法通过在内存操作数(而不是操作码本身)前面加 byte ptr、word ptr和 dword ptr来指定大小。所以Intelmov al, byte ptr fooATTmovb foo, %al在 ATT 语法中中间形式长跳转和调用是 lcall/ljmp $section, $offsetIntel 语法是 call/jmp far section:offset。在 ATT 语法中远返回指令是 lret $stack-adjust而 Intel 使用 ret far stack-adjust。在这两种汇编器中寄存器的名称是一样的但是因为寻址模式不同使用它们的语法是不同的。另外GAS 中的汇编器指令以 “.” 开头但是在 NASM 中不是。.text部分是处理器开始执行代码的地方。global(或者 GAS 中的 .globl或 .global)关键字用来让一个符号对链接器可见可以供其他链接对象模块使用。在清单 1 的 NASM 部分中global _start让 _start符号成为可见的标识符这样链接器就知道跳转到程序中的什么地方并开始执行。与 NASM 一样GAS 寻找这个 _start标签作为程序的默认进入点。在 GAS 和 NASM 中标签都以冒号结尾。中断是一种通知操作系统需要它的服务的一种方法。第 16 行中的 int指令执行这个工作。GAS 和 NASM 对中断使用同样的助记符。GAS 使用 0x前缀指定十六进制数字NASM 使用 h后缀。因为在 GAS 中中间操作数带 $前缀所以 80 hex 是 $0x80。int $0x80(或 NASM 中的 80h)用来向 Linux 请求一个服务。服务编码放在 EAX 寄存器中。EAX 中存储的值是 1(代表 Linux exit 系统调用)这请求程序退出。EBX 寄存器包含退出码(在这个示例中是 2)也就是返回给操作系统的一个数字。(可以在命令提示下输入 echo $?来检查这个数字。)最后讨论一下注释。GAS 支持 C 风格(/* */)、C 风格(//)和 shell 风格(#)的注释。NASM 支持以 “;” 字符开头的单行注释。回页首变量和内存访问本节首先给出一个示例程序它寻找三个数字中的最大者。清单 2. 寻找三个数字中最大者的程序行号NASMGAS001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031; Data section beginssection .datavar1 dd 40var2 dd 20var3 dd 30section .textglobal _start_start:; Move the contents of variablesmov ecx, [var1]cmp ecx, [var2]jg check_third_varmov ecx, [var2]check_third_var:cmp ecx, [var3]jg _exitmov ecx, [var3]_exit:mov eax, 1mov ebx, ecxint 80h// Data section begins.section .datavar1:.int 40var2:.int 20var3:.int 30.section .text.globl _start_start:# move the contents of variablesmovl (var1), %ecxcmpl (var2), %ecxjg check_third_varmovl (var2), %ecxcheck_third_var:cmpl (var3), %ecxjg _exitmovl (var3), %ecx_exit:movl $1, %eaxmovl %ecx, %ebxint $0x80在上面的内存变量声明中可以看到几点差异。NASM 分别使用 dd、dw和 db指令声明 32 位、16 位和 8 位数字而 GAS 分别使用 .long、.int和 .byte。GAS 还有其他指令比如 .ascii、.asciz和 .string。在 GAS 中像声明其他标签一样声明变量(使用冒号)但是在 NASM 中只需在内存分配指令(dd、dw等等)前面输入变量名后面加上变量的值。清单 2 中的第 18 行演示内存直接寻址模式。NASM 使用方括号间接引用一个内存位置指向的地址值[var1]。GAS 使用圆括号间接引用同样的值(var1)。本文后面讨论其他寻址模式的使用方法。回页首使用宏清单 3 演示本节讨论的概念它接受用户名作为输入并返回一句问候语。清单 3. 读取字符串并向用户显示问候语的程序行号NASMGAS001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062section .dataprompt_str db Enter your name: ; $ is the location counterSTR_SIZE equ $ - prompt_strgreet_str db Hello GSTR_SIZE equ $ - greet_strsection .bss; Reserve 32 bytes of memorybuff resb 32; A macro with two parameters; Implements the write system call%macro write 2mov eax, 4mov ebx, 1mov ecx, %1mov edx, %2int 80h%endmacro; Implements the read system call%macro read 2mov eax, 3mov ebx, 0mov ecx, %1mov edx, %2int 80h%endmacrosection .textglobal _start_start:write prompt_str, STR_SIZEread buff, 32; Read returns the length in eaxpush eax; Print the hello textwrite greet_str, GSTR_SIZEpop edx; edx length returned by readwrite buff, edx_exit:mov eax, 1mov ebx, 0int 80h.section .dataprompt_str:.ascii Enter Your Name: pstr_end:.set STR_SIZE, pstr_end - prompt_strgreet_str:.ascii Hello gstr_end:.set GSTR_SIZE, gstr_end - greet_str.section .bss// Reserve 32 bytes of memory.lcomm buff, 32// A macro with two parameters// implements the write system call.macro write str, str_sizemovl $4, %eaxmovl $1, %ebxmovl \str, %ecxmovl \str_size, %edxint $0x80.endm// Implements the read system call.macro read buff, buff_sizemovl $3, %eaxmovl $0, %ebxmovl \buff, %ecxmovl \buff_size, %edxint $0x80.endm.section .text.globl _start_start:write $prompt_str, $STR_SIZEread $buff, $32// Read returns the length in eaxpushl %eax// Print the hello textwrite $greet_str, $GSTR_SIZEpopl %edx// edx length returned by readwrite $buff, %edx_exit:movl $1, %eaxmovl $0, %ebxint $0x80本节要讨论宏以及 NASM 和 GAS 对它们的支持。但是在讨论宏之前先与其他几个特性做一下比较。清单 3 演示了未初始化内存的概念这是用 .bss部分指令(第 14行)定义的。BSS 代表 “block storage segment” (原来是以一个符号开头的块)BSS部分中保留的内存在程序启动时初始化为零。BSS 部分中的对象只有一个名称和大小没有值。与数据部分中不同BSS部分中声明的变量并不实际占用空间。NASM 使用 resb、resw和 resd关键字在 BSS 部分中分配字节、字和双字空间。GAS 使用 .lcomm关键字分配字节级空间。请注意在这个程序的两个版本中声明变量名的方式。在 NASM 中变量名前面加 resb(或 resw或 resd)关键字后面是要保留的空间量在 GAS 中变量名放在 .lcomm关键字的后面然后是一个逗号和要保留的空间量。NASMvarname resb sizeGAS.lcomm varname, size清单 3 还演示了位置计数器的概念(第 6 行)。NASM 提供特殊的变量($和 $$变量)来操作位置计数器。在 GAS 中无法操作位置计数器必须使用标签计算下一个存储位置(数据、指令等等)。例如为了计算一个字符串的长度在 NASM 中会使用以下指令prompt_str db Enter your name: STR_SIZE equ $ - prompt_str; $ is the location counter$提供位置计数器的当前值从这个位置计数器中减去标签的值(所有变量名都是标签)就会得出标签的声明和当前位置之间的字节数。equ用来将变量 STR_SIZE 的值设置为后面的表达式。GAS 中使用的相似指令如下prompt_str:.ascii Enter Your Name: pstr_end:.set STR_SIZE, pstr_end - prompt_str末尾标签(pstr_end)给出下一个位置地址减去启始标签地址就得出大小。还要注意这里使用 .set将变量 STR_SIZE 的值设置为逗号后面的表达式。也可以使用对应的 .equ。在 NASM 中没有与 GAS 的 set指令对应的指令。正如前面提到的清单 3 使用了宏(第 21 行)。在 NASM 和 GAS中存在不同的宏技术包括单行宏和宏重载但是这里只关注基本类型。宏在汇编程序中的一个常见用途是提高代码的清晰度。通过创建可重用的宏可以避免重复输入相同的代码段这不但可以避免重复而且可以减少代码量从而提高代码的可读性。NASM 使用 %beginmacro指令声明宏用 %endmacro指令结束声明。%beginmacro指令后面是宏的名称。宏名称后面是一个数字这是这个宏需要的宏参数数量。在 NASM 中宏参数是从 1 开始连续编号的。也就是说宏的第一个参数是 %1第二个是 %2第三个是 %3以此类推。例如%beginmacro macroname 2mov eax, %1mov ebx, %2%endmacro这创建一个有两个参数的宏第一个参数是 %1第二个参数是 %2。因此对上面的宏的调用如下所示macroname 5, 6还可以创建没有参数的宏在这种情况下不指定任何数字。现在看看 GAS 如何使用宏。GAS 提供 .macro和 .endm指令来创建宏。.macro指令后面跟着宏名称后面可以有参数也可以没有参数。在 GAS 中宏参数是按名称指定的。例如.macro macroname arg1, arg2movl \arg1, %eaxmovl \arg2, %ebx.endm当在宏中使用宏参数名称时在名称前面加上一个反斜线。如果不这么做链接器会把名称当作标签而不是参数因此会报告错误。函数、外部例程和堆栈本节的示例程序在一个整数数组上实现选择排序。清单 4. 在整数数组上实现选择排序行号NASMGAS001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145section .dataarray db89, 10, 67, 1, 4, 27, 12, 34,86, 3ARRAY_SIZE equ $ - arrayarray_fmt db %d, 0usort_str db unsorted array:, 0sort_str db sorted array:, 0newline db 10, 0section .textextern putsglobal _start_start:push usort_strcall putsadd esp, 4push ARRAY_SIZEpush arraypush array_fmtcall print_array10add esp, 12push ARRAY_SIZEpush arraycall sort_routine20; Adjust the stack pointeradd esp, 8push sort_strcall putsadd esp, 4push ARRAY_SIZEpush arraypush array_fmtcall print_array10add esp, 12jmp _exitextern printfprint_array10:push ebpmov ebp, espsub esp, 4mov edx, [ebp 8]mov ebx, [ebp 12]mov ecx, [ebp 16]mov esi, 0push_loop:mov [ebp - 4], ecxmov edx, [ebp 8]xor eax, eaxmov al, byte [ebx esi]push eaxpush edxcall printfadd esp, 8mov ecx, [ebp - 4]inc esiloop push_looppush newlinecall printfadd esp, 4mov esp, ebppop ebpretsort_routine20:push ebpmov ebp, esp; Allocate a word of space in stacksub esp, 4; Get the address of the arraymov ebx, [ebp 8]; Store array sizemov ecx, [ebp 12]dec ecx; Prepare for outer loop herexor esi, esiouter_loop:; This stores the min indexmov [ebp - 4], esimov edi, esiinc ediinner_loop:cmp edi, ARRAY_SIZEjge swap_varsxor al, almov edx, [ebp - 4]mov al, byte [ebx edx]cmp byte [ebx edi], aljge check_nextmov [ebp - 4], edicheck_next:inc edijmp inner_loopswap_vars:mov edi, [ebp - 4]mov dl, byte [ebx edi]mov al, byte [ebx esi]mov byte [ebx esi], dlmov byte [ebx edi], alinc esiloop outer_loopmov esp, ebppop ebpret_exit:mov eax, 1mov ebx, 0int 80h.section .dataarray:.byte 89, 10, 67, 1, 4, 27, 12,34, 86, 3array_end:.equ ARRAY_SIZE, array_end - arrayarray_fmt:.asciz %dusort_str:.asciz unsorted array:sort_str:.asciz sorted array:newline:.asciz \n.section .text.globl _start_start:pushl $usort_strcall putsaddl $4, %esppushl $ARRAY_SIZEpushl $arraypushl $array_fmtcall print_array10addl $12, %esppushl $ARRAY_SIZEpushl $arraycall sort_routine20# Adjust the stack pointeraddl $8, %esppushl $sort_strcall putsaddl $4, %esppushl $ARRAY_SIZEpushl $arraypushl $array_fmtcall print_array10addl $12, %espjmp _exitprint_array10:pushl %ebpmovl %esp, %ebpsubl $4, %espmovl 8(%ebp), %edxmovl 12(%ebp), %ebxmovl 16(%ebp), %ecxmovl $0, %esipush_loop:movl %ecx, -4(%ebp)movl 8(%ebp), %edxxorl %eax, %eaxmovb (%ebx, %esi, 1), %alpushl %eaxpushl %edxcall printfaddl $8, %espmovl -4(%ebp), %ecxincl %esiloop push_looppushl $newlinecall printfaddl $4, %espmovl %ebp, %esppopl %ebpretsort_routine20:pushl %ebpmovl %esp, %ebp# Allocate a word of space in stacksubl $4, %esp# Get the address of the arraymovl 8(%ebp), %ebx# Store array sizemovl 12(%ebp), %ecxdecl %ecx# Prepare for outer loop herexorl %esi, %esiouter_loop:# This stores the min indexmovl %esi, -4(%ebp)movl %esi, %ediincl %ediinner_loop:cmpl $ARRAY_SIZE, %edijge swap_varsxorb %al, %almovl -4(%ebp), %edxmovb (%ebx, %edx, 1), %alcmpb %al, (%ebx, %edi, 1)jge check_nextmovl %edi, -4(%ebp)check_next:incl %edijmp inner_loopswap_vars:movl -4(%ebp), %edimovb (%ebx, %edi, 1), %dlmovb (%ebx, %esi, 1), %almovb %dl, (%ebx, %esi, 1)movb %al, (%ebx, %edi, 1)incl %esiloop outer_loopmovl %ebp, %esppopl %ebpret_exit:movl $1, %eaxmovl 0, %ebxint $0x80初看起来清单 4 似乎非常复杂实际上它是非常简单的。这个清单演示了函数、各种内存寻址方案、堆栈和库函数的使用方法。这个程序对包含 10 个数字的数组进行排序并使用外部 C 库函数 puts和 printf输出未排序数组和已排序数组的完整内容。为了实现模块化和介绍函数的概念排序例程本身实现为一个单独的过程数组输出例程也是这样。我们来逐一分析一下。在声明数据之后这个程序首先执行对 puts的调用(第 31 行)。puts函数在控制台上显示一个字符串。它惟一的参数是要显示的字符串的地址通过将字符串的地址压入堆栈(第 30 行)将这个参数传递给它。在 NASM 中任何不属于我们的程序但是需要在链接时解析的标签都必须预先定义这就是 extern关键字的作用(第 24 行)。GAS 没有这样的要求。在此之后字符串的地址 usort_str被压入堆栈(第 30 行)。在 NASM 中内存变量(比如 usort_str)代表内存位置本身所以 push usort_str这样的调用实际上是将地址压入堆栈的顶部。但是在 GAS 中变量 usort_str必须加上前缀 $这样它才会被当作地址。如果不加前缀 $那么会将内存变量代表的实际字节压入堆栈而不是地址。因为在堆栈中压入一个变量会让堆栈指针移动一个双字所以给堆栈指针加 4(双字的大小)(第 32 行)。现在将三个参数压入堆栈并调用 print_array10函数(第 37 行)。在 NASM 和 GAS 中声明函数的方法是相同的。它们仅仅是通过 call指令调用的标签。在调用函数之后ESP 代表堆栈的顶部。esp 4代表返回地址esp 8代表函数的第一个参数。在堆栈指针上加上双字变量的大小(即 esp 12、esp 16等等)就可以访问所有后续参数。在函数内部通过将 esp复制到 ebp(第 62 行)创建一个局部堆栈框架。和程序中的处理一样还可以为局部变量分配空间(第 63 行)。方法是从 esp中减去所需的字节数。esp – 4表示为一个局部变量分配 4 字节的空间只要堆栈中有足够的空间容纳局部变量就可以继续分配。清单 4 演示了基间接寻址模式(第 64 行)也就是首先取得一个基地址然后在它上面加一个偏移量从而到达最终的地址。在清单的 NASM 部分中[ebp 8]和 [ebp – 4](第 71 行)就是基间接寻址模式的示例。在 GAS 中寻址方法更简单一些4(%ebp)和 -4(%ebp)。在 print_array10例程中在 push_loop标签后面可以看到另一种寻址模式(第 74 行)。在 NASM 和 GAS 中的表示方法如下NASMmov al, byte [ebx esi]GASmovb (%ebx, %esi, 1), %al这种寻址模式称为基索引寻址模式。这里有三项数据一个是基地址第二个是索引寄存器第三个是乘数。因为不可能决定从一个内存位置开始访问的字节数所以需要用一个方法计算访问的内存量。NASM 使用字节操作符告诉汇编器要移动一个字节的数据。在 GAS中用一个乘数和助记符中的 b、w或 l后缀(例如 movb)来解决这个问题。初看上去 GAS 的语法似乎有点儿复杂。GAS 中基索引寻址模式的一般形式如下%segment:ADDRESS (, index, multiplier)或%segment:(offset, index, multiplier)或%segment:ADDRESS(base, index, multiplier)使用这个公式计算最终的地址ADDRESS or offset base index * multiplier.因此要想访问一个字节就使用乘数 1对于字乘数是 2对于双字乘数是 4。当然NASM 使用的语法比较简单。上面的公式在 NASM 中表示为Segment:[ADDRESS or offset index * multiplier]为了访问 1、2 或 4 字节的内存在这个内存地址前面分别加上 byte、word或 dword。其他方面清单 5 读取命令行参数的列表将它们存储在内存中然后输出它们。清单 5. 读取命令行参数将它们存储在内存中然后输出它们行号NASMGAS001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061section .data; Command table to store at most; 10 command line argumentscmd_tbl:%rep 10dd 0%endrepsection .textglobal _start_start:; Set up the stack framemov ebp, esp; Top of stack contains the; number of command line arguments.; The default value is 1mov ecx, [ebp]; Exit if arguments are more than 10cmp ecx, 10jg _exitmov esi, 1mov edi, 0; Store the command line arguments; in the command tablestore_loop:mov eax, [ebp esi * 4]mov [cmd_tbl edi * 4], eaxinc esiinc ediloop store_loopmov ecx, edimov esi, 0extern putsprint_loop:; Make some local spacesub esp, 4; puts function corrupts ecxmov [ebp - 4], ecxmov eax, [cmd_tbl esi * 4]push eaxcall putsadd esp, 4mov ecx, [ebp - 4]inc esiloop print_loopjmp _exit_exit:mov eax, 1mov ebx, 0int 80h.section .data// Command table to store at most// 10 command line argumentscmd_tbl:.rept 10.long 0.endr.section .text.globl _start_start:// Set up the stack framemovl %esp, %ebp// Top of stack contains the// number of command line arguments.// The default value is 1movl (%ebp), %ecx// Exit if arguments are more than 10cmpl $10, %ecxjg _exitmovl $1, %esimovl $0, %edi// Store the command line arguments// in the command tablestore_loop:movl (%ebp, %esi, 4), %eaxmovl %eax, cmd_tbl( , %edi, 4)incl %esiincl %ediloop store_loopmovl %edi, %ecxmovl $0, %esiprint_loop:// Make some local spacesubl $4, %esp// puts functions corrupts ecxmovl %ecx, -4(%ebp)movl cmd_tbl( , %esi, 4), %eaxpushl %eaxcall putsaddl $4, %espmovl -4(%ebp), %ecxincl %esiloop print_loopjmp _exit_exit:movl $1, %eaxmovl $0, %ebxint $0x80清单 5 演示在汇编程序中重复执行指令的方法。很自然这种结构称为重复结构。在 GAS 中重复结构以 .rept指令开头(第 6 行)。用一个 .endr指令结束这个指令(第 8 行)。.rept后面是一个数字它指定 .rept/.endr结构中表达式重复执行的次数。这个结构中的任何指令都相当于编写这个指令 count次每次重复占据单独的一行。例如如果次数是 3.rept 3movl $2, %eax.endr就相当于movl $2, %eaxmovl $2, %eaxmovl $2, %eax在 NASM 中在预处理器级使用相似的结构。它以 %rep指令开头以 %endrep结尾。%rep指令后面是一个表达式(在 GAS 中 .rept指令后面是一个数字)%rep nop%endrep在 NASM 中还有另一种结构times指令。与 %rep相似它也在汇编级起作用后面也是一个表达式。例如上面的 %rep结构相当于times nop以下代码%rep 3mov eax, 2%endrep相当于times 3 mov eax, 2它们都相当于mov eax, 2mov eax, 2mov eax, 2在清单 5 中使用 .rept(或 %rep)指令为 10 个双字创建内存数据区。然后从堆栈一个个地访问命令行参数并将它们存储在内存区中直到命令表填满。在这两种汇编器中访问命令行参数的方法是相似的。ESP(堆栈顶部)存储传递给程序的命令行参数数量默认值是 1(表示没有命令行参数)。esp 4存储第一个命令行参数这总是从命令行调用的程序的名称。esp 8、esp 12等存储后续命令行参数。还要注意清单 5 中从两边访问内存命令表的方法。这里使用内存间接寻址模式(第 31 行)访问命令表还使用了 ESI(和 EDI)中的偏移量和一个乘数。因此NASM 中的 [cmd_tbl esi * 4]相当于 GAS 中的 cmd_tbl(, %esi, 4)。结束语尽管在这两种汇编器之间存在实质性的差异但是在这两种形式之间进行转换并不困难。您最初可能觉得 ATT 语法难以理解但是掌握了它之后它其实和 Intel 语法同样简单。
http://www.sadfv.cn/news/161302/

相关文章:

  • 百度统计网站速度诊断工具网站建设常用软件
  • 云速建站可以建个人网站吗怎么做seo信息优化
  • 域名申请后怎么建网站网络规划与设计师
  • 怎么做网站作业考研培训班哪个机构比较好
  • h5制作网站公司义乌app制作公司
  • 网站的模块重庆vi设计公司
  • 镇江企业网站排名优化怎么新建一个网站
  • 深圳 赢客创想网络技术股份有限公司 网站建设小程序制作免费吗
  • 杭州建设企业网站的清溪仿做网站
  • 医疗网站平台建设方案建e网室内设计网现代轻奢
  • 网站下载到本地广州冼村
  • 河南建设工程招标网站wordpress 随机范围点击量
  • 上海建站网重庆荣昌网站建设
  • 友情链接有哪些信息流优化师培训机构
  • winserverfrp可以做网站吗阳江招聘网最新招聘找工作
  • 南京协会网站建设wordpress新建页面连接无法访问
  • 优质做网站照片做视频的软件 模板下载网站
  • flash网站php源码wordpress.net
  • 个人网站开发要多久百度人工服务
  • 网站建设实物实训目的html框架
  • 比特币交易网站可以做空吗职业生涯规划大赛活动总结
  • 给别人做网站收多少钱权威发布的含义
  • 做网站最好的软件网站建设倒计时单页源码
  • 工信部网站备案查询 验证码错误买源码做网站
  • 关于网站制作的文案新网域名续费
  • 萍乡网站开发公司免费搭建商业网站
  • 一条龙网站建设做动物网站的原因是
  • 做网站后台需要什么知识暴雪官网
  • 网站绝对布局手机h5页面怎么制作
  • 常见的网站建设类型都有哪些网站建设制作及推广