NASM компилирует адреса меток x86_64 ASM на 256 байтов в Mach-O при использовании нескольких объявлений БД?

Короче когда у меня несколько db разделы в моем .data раздел, скомпилированные адреса / метки отключены при компиляции NASM. В моем тестировании они были отключены на 256 байтов в полученном двоичном файле Mach-O.

Программное обеспечение, которое я использую:

  • OS X 10.10.5
  • nasm NASM версия 2.11.08, установленная через Homebrew, как требуется для x84_64 ASM
  • gobjdump GNU objdump (GNU Binutils) 2.25.1, установленный через Homebrew
  • clang Apple LLVM версии 6.1.0 (clang-602.0.53) (на основе LLVM 3.6.0svn)

Что работает:

Возьмем, к примеру, следующую сборку NASM "Hello World".

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 прошлое msgb, или же 100001100 (по этому адресу нулевые байты, что не приводит к выводу). Проверяя двоичный файл в шестнадцатеричном редакторе, я нахожу фактическое msga строка со смещением 1000или адрес 100001000, Означает, что адрес в скомпилированном двоичном файле теперь отключен 0x100/256 байт, просто потому что теперь есть второй db этикетка. Какие?!?


Простите, извините за обходной путь:

В качестве эксперимента я решил попробовать поставить оба db разделы на отдельные файлы ASM/ объект и связывание всех трех вместе. Это работает.

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!

Хотя это работает, мне трудно поверить, что это лучшее решение.


Что не так?

Конечно, должен быть способ иметь несколько db метки в одном файле ASM? Я что-то не так делаю, когда пишу ASM? Это ошибка в NASM? Это ожидаемое поведение как-то, в таком случае почему? Мой обходной путь - дополнительная работа и беспорядок, поэтому я был бы очень признателен за любую помощь в этом.

2 ответа

Решение

Да, это ошибка в Nasm-2.11.08. Nasm-2.11.06 должен работать. Nasm-2.11.09rc1 должен работать (?). Извините насчет этого!

Связанная проблема может быть найдена здесь:

Ошибка 3392306 - проблема с относительной адресацией и разделом данных

Текущая версия 2.11.08, доступная Homebrew, исправляет эту проблему следующим файлом 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, эта проблема должна быть решена.

Другие вопросы по тегам