Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.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 在GNU as.intel_语法中区分内存和常量_Assembly_X86 64_Gnu Assembler_Intel Syntax - Fatal编程技术网

Assembly 在GNU as.intel_语法中区分内存和常量

Assembly 在GNU as.intel_语法中区分内存和常量,assembly,x86-64,gnu-assembler,intel-syntax,Assembly,X86 64,Gnu Assembler,Intel Syntax,我有一条用英特尔语法编写的指令(使用gas作为汇编程序),如下所示: mov rdx, msg_size ... msg: .ascii "Hello, world!\n" .set msg_size, . - msg 但是,正如我所期望的那样,mov指令正在被组装成mov0xe,%rdx,而不是mov$0xe,%rdx。我应该如何编写第一条指令(或msg_size的定义)以获得预期的行为?使用mov-edx,OFFSET-symbol获取符号“address”作为立即数,而不是从中

我有一条用英特尔语法编写的指令(使用gas作为汇编程序),如下所示:

mov rdx, msg_size
...
msg: .ascii "Hello, world!\n"
     .set msg_size, . - msg

但是,正如我所期望的那样,mov指令正在被组装成
mov0xe,%rdx
,而不是
mov$0xe,%rdx
。我应该如何编写第一条指令(或
msg_size
的定义)以获得预期的行为?

使用
mov-edx,OFFSET-symbol
获取符号“address”作为立即数,
而不是从中加载作为地址。这适用于实际标签地址以及使用
.set
设置为整数的符号

对于64位代码中的
msg
地址(不是
msg\u size
assemble time常量),您可能需要
leardx,[RIP+msg]
用于静态地址不适合32位的饼图可执行文件


在GAS
.intel\u语法noprefix
模式下:

  • 偏移符号
    的工作原理类似于AT&T
    $symbol
    。这有点像MASM
  • symbol
    的工作原理与AT&T
    symbol
    (即解引用)的未知符号类似
  • 在GAS和NASM/YASM中,
    [symbol]
    始终是有效地址,而不是立即地址
    LEA
    不会从地址加载,但它仍然使用内存操作数机器编码。()

符号的解释取决于声明的顺序
GAS是一个单程汇编程序(返回并填充
符号值(一旦已知)

当它第一次遇到该行时,它决定了
mov rdx,symbol
的操作码和编码。早期的
msize=。-msg
.eq
/
.set
将使其选择
mov reg,imm32
,但稍后的指令仍不可见

对于尚未定义的符号,默认假设是
symbol
是某个节中的地址(就像您使用
symbol:
.set symbol.
这样的标签来定义它)。由于GAS
.intel\u syntax
类似于MASM而不是NASM,因此裸符号被视为内存操作数

如果将
.set
msg_length=msg_end-msg
指令放在文件顶部,在引用它的指令之前,它们将组合为
mov reg,imm32
mov immediate。(与AT&T语法不同,在AT&T语法中,即使对于像
1234
这样的数字文本,也总是需要一个
$
作为立即数)

例如:源代码和反汇编与
objdump-dS交织在一起:
gcc-g-cfoo.s
组装,用
objdump-drwC-s-Mintel-foo.o
反汇编(用
as--version
=GNU汇编程序(GNU-Binutils)2.34)。我们得到这个:

0000000000000000 <l1>:
.intel_syntax noprefix

l1:     
mov eax, OFFSET equsym
   0:   b8 01 00 00 00          mov    eax,0x1
mov eax, equsym            #### treated as a load
   5:   8b 04 25 01 00 00 00    mov    eax,DWORD PTR ds:0x1
mov rax, big               #### 32-bit sign-extended absolute load address, even though the constant was unsigned positive
   c:   48 8b 04 25 aa aa aa aa         mov    rax,QWORD PTR ds:0xffffffffaaaaaaaa
mov rdi, OFFSET label
  14:   48 c7 c7 00 00 00 00    mov    rdi,0x0  17: R_X86_64_32S        .text+0x1b

000000000000001b <label>:

label:
nop
  1b:   90                      nop

.equ equsym, . - label            # equsym = 1
big = 0xaaaaaaaa

mov eax, OFFSET equsym
  1c:   b8 01 00 00 00          mov    eax,0x1
mov eax, equsym           #### treated as an immediate
  21:   b8 01 00 00 00          mov    eax,0x1
mov rax, big              #### constant doesn't fit in 32-bit sign extended, assembler can see it when picking encoding so it picks movabs imm64
  26:   48 b8 aa aa aa aa 00 00 00 00   movabs rax,0xaaaaaaaa
0000000000000000:
.intel_语法noprefix
l1:
mov eax,偏移量相等
0:b8 01 00 mov eax,0x1
mov eax,Equalsym#######作为负载处理
5:8b 04 25 01 00 mov eax,DWORD PTR ds:0x1
mov rax,big######32位符号扩展绝对加载地址,即使常量为无符号正
c:48 8b 04 25 aa移动rax,QWORD PTR ds:0xffffffffaaaaaaaa
胶印标签
14:48 c7 c7 00 mov rdi,0x0 17:R_X86_64_32S.text+0x1b
00000000000000 1B:
标签:
不
1b:90无
.equ equsym,.-标签#eqsym=1
大=0xaaaaaa
mov eax,偏移量相等
1c:b8 01 00 mov eax,0x1
mov eax,eqsym#########被视为直接
21:b8 01 00 mov eax,0x1
mov-rax,big#####常量不适合32位符号扩展,汇编程序在选择编码时可以看到它,所以它选择movab imm64
26:48 b8 aa aa 00 00 movabs rax,0xAAAAA
使用
mov-edx,OFFSET-msg_-size
将任何符号(甚至数字文字)视为立即数总是安全的,无论它是如何定义的。因此,它与AT&T
$
完全相同,只是当GAS已经知道符号值只是一个数字,而不是某个部分中的地址时,它是可选的为了保持一致性,最好始终使用
OFFSET msg_size
,这样,如果将来有程序员移动代码,那么代码的含义就不会改变
,这样数据部分和相关指令就不再是第一位了。(包括那些忘记了这些与大多数汇编程序不同的奇怪细节的未来用户。)

顺便说一句,是的同义词,还有一个用于设置值,该值也是
的同义词。set


操作数大小:通常使用32位,除非值需要64位
mov-rdx,偏移符号
将组合到
mov-r/m64,符号扩展\u-imm32
。除非它是一个负常量,而不是一个地址,否则在很短的长度内(远小于4GiB)不需要它。您也不希望地址为
movabsr64,imm64
;那太没效率了

在GNU/Linux下,在位置相关的可执行文件中写入
mov-edx,OFFSET-symbol
是安全的,事实上,您应该始终这样做,或者使用
leardx,[rip+symbol]
,除非您正在编写将加载到高2GB虚拟地址空间(例如内核)的代码,否则不要签署扩展32位立即数

有关PIE可执行文件是现代发行版中的默认文件的更多信息,请参见


提示:如果您知道AT&T或NASM语法,或NASM语法,请使用它生成所需的编码,然后使用
objdump-Mintel
反汇编,以找到
的正确语法。英特尔语法noprefx

但这在这里并没有帮助,因为反汇编只会在对象文件中显示数值文本,如
mov-edx,123
,而不是
mov-edx,OFFSET-name\u-not\u