查看“Opcode syntax”的源代码
←
Opcode syntax
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
AT&T语法 (如GAS所理解的,GNU汇编器) 是大多数非Intel平台上的标准语法,但在x86平台上仍然很少见。 但是,AT&T语法是GCC [[Inline Assembly|内联汇编]] 的默认语法,这是objdump在调试内核时将为你提供的语法。 NASM和FASM使用Intel语法,Intel语法是 [[Bochs]] 调试器在调试你的内核时提供的。 == 重要细节 == AT&T语法和Intel语法之间存在一些实质性差异,打算使用GNU工具的程序员应该意识到这一点。 转到AT&T语法时,需要寻找以下几个关键内容: * ''' 区分大小写: ''' MOVL与movl并不相同。 * ''' 数值基数: ''' 用C语言风格表示: 1表示十进制,01表示八进制,0x01表示十六进制。(不支持英特尔postfix-h语法。) * ''' 转义字符: ''' 特殊字符被写成C风格的转义 (\n,\",\#, \\,...)。 * ''' 注释: ''' C样式 (/* ... */) 或shell样式 (# ...)。 * ''' 指令语法: ''' 指令以句点开始 (“.align 4” 指在32位边界上对齐,“.word 0x1234” 等同于 “DW 1234h”)。 * ''' 字符串: ''' 使用特殊指令定义 .ascii (或.asciz用于零端字符串)。示例: msg: .ascii "Hello, World!\n"” * ''' 当前位置地址: ''' 用句点 (".",相当于Intel语法 "$") 表示。 * ''' 初始化内存: ''' 使用.fill完成 (大致相当于Intel语法 'times db')。 例: .fill 0x1fe - (. - START) , 1, 0 (其中 '1' 是以字节为单位的大小填充掩码,START是标记代码入口点的标签) 等于Intel语法 times 1FEh - ($-$$) db 0。 (.skip和.space指令可以以类似的方式使用。) * '''代码计数器''' 可以多次设置,使用.org指令 (如.org 0x1fe START,其中START是标记代码入口点的标签。 位置分配指令 '.=' 可以以相同的方式使用。 *'''16/32 bit code''' 可以通过 .code16 或 .code32 (分别相当于Intel语法 [BITS 16] 和 [BITS 32])来生成。 * ''' 目标CPU:''' 使用.arch指令设置。 即使您确定默认值为 “i386”,也可以设置它。 * ''' 标签声明: ''' 总是以冒号结尾。 * '''新标识符''' 假定出现在行的开头,而不是以冒号结尾,是等价语句的一部分,并且必须后跟等号和赋值。示例: FOO = 0xF00 * ''' 指令结束: ''' 用换行符或用分号指定; 后者主要在宏中看到,以允许多行代码。 * ''' 换行继续: ''' 与C一样,用反斜杠 ('\') 作为一行中的最后一个字符。这也主要用于宏中。 * ''' 寄存器: ''' 始终以百分号为前缀: %eax,%cs,%esp等。 * ''' 来源(Source),目的地(Destination): ''' 移动(Move),加载(Load),存储(Store)和类似的操作始终具有 “源,目的地” 顺序的操作数,这与Intel语法非常不同。 因此,“movl %eax, %ebx” 将%eax的值移动到, %ebx。 这是似乎最使人困惑的部分,因为它几乎与Intel语法相反: <pre>Opcode Register/Memory-being-modified, Data, Data</pre> * ''' 操作数大小后缀: ''' 后缀始终附加到指令 (x86上的ljmp、lcall和lret除外): movb表示 “move字节”,movw表示 “move字”,movl表示 “move长整形” 等。 * ''' 直接地址操作数: ''' 直接地址操作数没有前缀。因此,"movl foo, %eax" 将内存位置 “foo” 的内容移动到 %eax。 * ''' 立即操作数: ''' 立即操作数以美元符号 ($) 为前缀: “pushl $4” 将0x00000004推到堆栈上。这也适用于标签: "movl $foo, %eax" 将标签foo的值 (即变量foo的地址) 移动到 %eax。 * ''' 索引/间接操作数: ''' 索引/间接操作数语法: displacement (base, index, scale),如: movl %eax, %ss:8(%ebp, 2, 3) (相当于Intel语法 mov dword [ss:ebp + 2 * 3 + 8], eax,也就是说,它将 %eax的值移动到段%ss中的偏移 (%ebp + (2 *3) + 8)。 间接地址的五个操作数中的任何一个都可以省略。 * ''' 相对寻址: ''' 相对寻址默认情况下在所有跳转和调用指令中使用。要使用绝对寻址,操作数必须以星号 (*) 为前缀。 *'''Far jumps / calls / returns:''' 这些使用特殊的操作码 “ljmp” 、 “lcall” 和 “lret”。 AT&T语法的宏格式: <source lang="asm"> .macro <name> <args> <operations> .endm </source> 示例: <source lang="asm"> .macro write string movw string, %si call printstr .endm </source> 这将等同于NASM宏: <source lang="asm"> %macro write 1 mov si, %1 call printstr %endmacro </source> 此外,cpp和 [[M4]] 宏预处理器通常用于宏处理。 == 将小代码片段从Intel语法转换为AT&T == 你可以使用以下脚本将代码的短片段 (一行) 从Intel语法转换为AT&T语法: <source lang="bash">#!/bin/bash set -e # Usage: # # ./inteltoatt [16|32|64] "mov eax, eax \n xor ecx, edx" # case "$1" in 16|32|64) bits="$1" shift ;; *) bits="32" ;; esac code="$1" nasm="$(mktemp)" obj="$(mktemp)" objdump="$(mktemp)" case "$bits" in 16) m="i8086" ;; 32) m="i386" ;; 64) m="i386:x86-64" ;; esac echo -e "BITS $bits\n$code" > "$nasm" nasm "$nasm" -o "$obj" objdump -D -b binary -m $m -Maddr${bits},data${bits} "$obj" > "$objdump" lineno="$(egrep -m 1 -n '<\.data>\:$' "$objdump" | cut -d':' -f1)" lineno=$((lineno+1)) tail -n +$lineno "$objdump" </source> == 另见 == === 外部链接 === *[http://www.delorie.com/djgpp/v2faq/faq17_1.html DJGPP AT&T Assembly Tutorial] *[http://asm.sourceforge.net//howto/Assembly-HOWTO.html Linux Assembly HOWTO] *[https://savannah.nongnu.org/projects/gas-user/ GAS/AS End User Help Project] *[https://savannah.nongnu.org/projects/pgubook/ Programming from the Ground Up] [[Category:Assembly]]
返回至“
Opcode syntax
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息