使用多个db声明时,NASM编译x86_64 ASM标签在Mach-O中关闭256个字节?

时间:2015-09-09 00:27:04

标签: assembly nasm x86-64 mach-o data-segment

简而言之,当我的db部分中有多个.data部分时,编译的地址/标签在由NASM编译时关闭。在我的测试中,它们在生成的Mach-O二进制文件中关闭了256个字节。

我正在使用的软件:

  • OS X 10.10.5
  • nasm NASM版本2.11.08,根据x84_64 ASM的要求通过Homebrew安装
  • gobjdump GNU objdump(GNU Binutils)2.25.1,通过Homebrew安装
  • clang Apple LLVM版本6.1.0(clang-602.0.53)(基于LLVM 3.6.0svn)

什么有效:

以下面的“hello world”NASM程序集为例。

main.s

global _main

section .text
_main:
mov     rax, 0x2000004
mov     rdi, 1
lea     rsi, [rel msg]
mov     rdx, len
syscall

mov     rax, 0x2000001
mov     rdi, 0
syscall

section .data
msg:    db      "Hello, world!", 10
len:    equ     $ - msg

编译并运行:

/usr/local/bin/nasm -f macho64 -o main.o main.s
clang -o main main.o
./main

这很好用,并产生以下输出:

Hello, world!

什么不是:

现在,要添加另一条消息,我们只需要在数据部分添加另一个字符串,然后再添加另一个syscall。很简单。

main.s

global _main

section .text
_main:
mov     rax, 0x2000004
mov     rdi, 1
lea     rsi, [rel msga]
mov     rdx, lena
syscall

mov     rax, 0x2000004
mov     rdi, 1
lea     rsi, [rel msgb]
mov     rdx, lenb
syscall

mov     rax, 0x2000001
mov     rdi, 0
syscall

section .data
msga:    db      "Hello, world!", 10
lena:    equ     $ - msga
msgb:    db      "Break things!", 10
lenb:    equ     $ - msgb

编译并运行,和以前一样,我们得到:

Break things!

什么?!?我们不应该得到吗?:

Hello, world!
Break things!

出了什么问题?:

显然出现了问题。是时候拆解生成的二进制文件,看看我们得到了什么。

$ gobjdump -d -M intel main

_main生成以下内容:

0000000100000f7c <_main>:
   100000f7c:b8 04 00 00 02       mov    eax,0x2000004
   100000f81:bf 01 00 00 00       mov    edi,0x1
   100000f86:48 8d 35 73 01 00 00 lea    rsi,[rip+0x173]        # 100001100 <msgb+0xf2>
   100000f8d:ba 0e 00 00 00       mov    edx,0xe
   100000f92:0f 05                syscall 
   100000f94:b8 04 00 00 02       mov    eax,0x2000004
   100000f99:bf 01 00 00 00       mov    edi,0x1
   100000f9e:48 8d 35 69 00 00 00 lea    rsi,[rip+0x69]        # 10000100e <msgb>
   100000fa5:ba 0e 00 00 00       mov    edx,0xe
   100000faa:0f 05                syscall 
   100000fac:b8 01 00 00 02       mov    eax,0x2000001
   100000fb1:bf 00 00 00 00       mov    edi,0x0
   100000fb6:0f 05                syscall 

在评论# 100001100 <msgb+0xf2>中,我们可以看到它不是指向msga符号,而是指向0xf2过去msgb100001100(在这个地址有空字节,导致没有输出)。在十六进制编辑器中检查二进制文件,我在偏移msga或地址1000处找到实际的100001000字符串。这意味着编译后的二进制文件中的地址现在已被0x100 / 256个字节关闭,这仅仅是因为现在有第二个db标签。什么?!?

解决方法的遗憾:

作为一项实验,我决定尝试将两个db部分放入单独的ASM /目标文件中,并将所有3个部分链接在一起。这样做有效。

main.s

global _main
extern _msga
extern _lena
extern _msgb
extern _lenb

section .text
_main:
mov     rax, 0x2000004
mov     rdi, 1
lea     rsi, [rel _msga]
mov     rdx, _lena
syscall

mov     rax, 0x2000004
mov     rdi, 1
lea     rsi, [rel _msgb]
mov     rdx, _lenb
syscall

mov     rax, 0x2000001
mov     rdi, 0
syscall

msga.s

global _msga
global _lena

section .data
_msga:   db      "Hello, world!", 10
_lena:   equ     $ - _msga

msgb.s

global _msgb
global _lenb

section .data
_msgb:   db      "Break things!", 10
_lenb:   equ     $ - _msgb

编译并运行:

/usr/local/bin/nasm -f macho64 -o main.o main.s
/usr/local/bin/nasm -f macho64 -o msga.o msga.s
/usr/local/bin/nasm -f macho64 -o msgb.o msgb.s
clang -o main msga.o msgb.o main.o
./main

结果:

Hello, world!
Break things!

虽然这确实有效,但我发现很难相信这是最好的解决方案。

出了什么问题?

当然必须有一种方法可以在一个ASM文件中包含多个db标签?我在编写ASM的方式上做错了吗?这是NASM中的错误吗?是这种预期的行为,在这种情况下为什么?我的解决方法是额外的工作和混乱,所以我非常感谢你的任何帮助。

2 个答案:

答案 0 :(得分:6)

是的,这是Nasm-2.11.08中的一个错误。 Nasm-2.11.06应该可以工作。 Nasm-2.11.09rc1应该工作(?)。抱歉'回合那个!

答案 1 :(得分:1)

相关问题可在此处找到:

Bug 3392306 - Issue with relative addressing and data section

Homebrew提供的2.11.08当前版本使用以下diff文件修补此问题:

https://raw.githubusercontent.com/Homebrew/patches/7a329c65e/nasm/nasm_outmac64.patch

From 4920a0324348716d6ab5106e65508496241dc7a2 Mon Sep 17 00:00:00 2001
From: Cyrill Gorcunov <gorcunov@gmail.com>
Date: Sat, 9 May 2015 18:07:47 +0300
Subject: [PATCH] output: outmac64 -- Fix the case when first hit matches the
 symbol

In case if we're looking up for a symbol and it's first
one in symbol table we might endup with error because of
using GE here (78f477b35f) ending cycle with @nearest = NULL.

http://bugzilla.nasm.us/show_bug.cgi?id=3392306

Reprted-by: Benjamin Randazzo <benjamin@linuxcrashing.org>
Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 output/outmac64.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/output/outmac64.c b/output/outmac64.c
index c07dcbc..1d30e64 100644
--- a/output/outmac64.c
+++ b/output/outmac64.c
@@ -304,7 +304,7 @@ static struct symbol *get_closest_section_symbol_by_offset(uint8_t fileindex, in

     for (sym = syms; sym; sym = sym->next) {
         if ((sym->sect != NO_SECT) && (sym->sect == fileindex)) {
-            if ((int64_t)sym->value >= offset)
+            if ((int64_t)sym->value > offset)
                 break;
             nearest = sym;
         }
-- 
2.4.10.GIT

因此,如果您通过Homebrew进行安装,现在应该解决此问题。