2016-08-30 2 views
3

Недавно я начал изучать язык ассемблера для архитектуры Intel x86-64 с использованием YASM. При решении одной из задач, предложенной в книге (Ray Seyfarth), я пришел к следующей проблеме:gdb ведет себя по-разному для символов в .bss, против символов в .data

Когда я помещаю некоторые символы в буфер в разделе .bss, я все еще вижу пустую строку при отладке ее в gdb , Размещение символов в буфере в разделе .data отображается как ожидалось в gdb.

segment .bss 
result resb 75 
buf resw 100 
usage resq 1 

    segment .data 
str_test db 0, 0, 0, 0 

    segment .text 
    global main 
main: 
    mov rbx, 'A' 
    mov [buf], rbx   ; LINE - 1 STILL GET EMPTY STRING AFTER THAT INSTRUCTION 
    mov [str_test], rbx  ; LINE - 2 PLACES CHARACTER NICELY. 
    ret 

В БГД я получаю:

  • после LINE 1: x/s &buf, результат - 0x7ffff7dd2740 <buf>: ""

  • после LINE 2: x/s &str_test, результат - 0x601030: "A"

It выглядит как &buf не e оценивая правильный адрес, поэтому он все еще видит все нули. 0x7ffff7dd2740 не находится в BSS процесса, который отлаживается, в соответствии с его /proc/PID/maps, поэтому это не имеет смысла. Почему &buf оценивает с неправильным адресом, но &str_test оценивает на правильном адресе? Также не являются «глобальными» символами, но мы строили их с помощью отладочной информации.

Протестировано с GNU gdb (Ubuntu 7.10-1ubuntu2) 7.10 на x86-64 Ubuntu 15.10.

Я строю с

yasm -felf64 -Worphan-labels -gdwarf2 buf-test.asm 
gcc -g buf-test.o -o buf-test 

nm на исполняемом показывает правильные адреса символов:

$ nm -n buf-test  # numeric sort, heavily edited to omit symbols from glibc 
... 
0000000000601028 D __data_start 
0000000000601038 d str_test 
... 
000000000060103c B __bss_start 
0000000000601040 b result 
000000000060108b b buf 
0000000000601153 b usage 

(примечание редактора: я переписал много вопроса, потому что странность в реализации GDB поведение, а не asm!).

+0

Я в основном переписал вопрос, так как ваш asm * был * работает. Проблема заключалась в том, что '& buf' в gdb был каким-то странным адресом в стеке. '0x7ffff ...' адреса - это адреса стека в x86-64 Linux. bss и адреса данных всегда находятся на низком уровне 2 ГБ (поэтому они вписываются в подписанные 32-битные целые числа, потому что многие инструкции x86-64 используют расширенные символы 'imm32', например' add rax, symbol' использует 'add r/m64 , imm64' кодировка). Во всяком случае, я тестировал себя на своем рабочем столе x86-64 и воспроизводил странность gdb, не найдя способ получить правильный адрес 'buf' в выражении gdb. –

+0

Другой ключ, по которому вы получаете неправильный адрес, состоит в том, что он равен 16B (последняя шестнадцатеричная цифра равна 0), но мы знаем, что 'buf' не должно быть. Он следует за «resb 75», а начало bss обычно выравнивается по 16B (как мы видим, «результат» находится в выходе nm. И да, эти адреса символов - это место, где исполняемый файл будет фактически отображаться каждый раз, когда вы Запустите его, потому что он не перемещается. Код для исполняемых файлов Linux не обязательно должен быть независимым от позиции, в отличие от динамических библиотек, которые необходимы (скомпилируйте с '-fPIC' или избегайте абсолютных адресов в рукописном asm). –

+0

Спасибо, Питер , как я понимаю, это поведение gdb, возможно ли справиться с ним и поместить символы как-то в раздел .bss. Некорректная позиция buf в стеке вместо .bss меня раздражает, и я не понимаю, почему это так. Должен ли я выравнивать buf каким-то образом? –

ответ

2

glibc включает в себя символ по имени buf, а также.

(gdb) info variables ^buf$ 
All variables matching regular expression "^buf$": 

File strerror.c: 
static char *buf; 

Non-debugging symbols: 
0x000000000060108b buf   <-- this is our buf 
0x00007ffff7dd6400 buf   <-- this is glibc's buf 

gdb происходит, чтобы выбрать символ из glibc над символом из исполняемого файла. Вот почему ptype buf показывает char *.

Использование другого имени для буфера позволяет избежать ошибки, так же как и global buf сделать его глобальным. Кроме того, не было бы проблемы, если вы написали отдельную программу, которая не связывала Libc (т.е. определить _start и сделать систему выхода вызова вместо запуска ret)


Обратите внимание, что 0x00007ffff7dd6400 (адрес buf в моей системе; отличная от вашей) не Фактически адрес стека. Он визуально выглядит как адрес стека, но это не так: у него есть другое число f цифр после 7. Извините за эту путаницу в комментариях и более раннее изменение вопроса.

Общие библиотеки также загружаются в верхней части the low 47 bits of virtual address space, рядом с которым отображается стек. Они независимы от позиции, но пространство BSS библиотеки должно быть в нужном месте относительно его кода. Еще раз проверьте /proc/PID/maps, gdb's &buf на самом деле находится в блоке rwx анонимной памяти (не привязанный к какому-либо файлу) рядом с отображением для libc-2.21.so.

7ffff7a0f000-7ffff7bcf000 r-xp 00000000 09:7f 17031175  /lib/x86_64-linux-gnu/libc-2.21.so 
7ffff7bcf000-7ffff7dcf000 ---p 001c0000 09:7f 17031175  /lib/x86_64-linux-gnu/libc-2.21.so 
7ffff7dcf000-7ffff7dd3000 r-xp 001c0000 09:7f 17031175  /lib/x86_64-linux-gnu/libc-2.21.so 
7ffff7dd3000-7ffff7dd5000 rwxp 001c4000 09:7f 17031175  /lib/x86_64-linux-gnu/libc-2.21.so 
7ffff7dd5000-7ffff7dd9000 rwxp 00000000 00:00 0  <--- &buf is in this mapping 
... 
7ffffffdd000-7ffffffff000 rwxp 00000000 00:00 0    [stack]  <---- more FFs before the first non-FF than in &buf. 

Нормальная call инструкция с кодировкой rel32 не может достичь функции библиотеки, но это не нужно, потому что GNU/Linux разделяемые библиотеки должны поддерживать символ взаиморасположение, поэтому call с до функций библиотеки на самом деле прыгать к PLT, где косвенный jmp (с указателем от GOT) отправляется в конечный пункт назначения.

+0

Теперь ясно, что это было банальное совпадение имени с buf в libc, сопоставленное где-то рядом со стеклом. Поэтому стоит выбирать собственные имена для меток, переменных. Спасибо, Питер. –

+0

@BulatM: у вас, вероятно, не было бы проблем, если бы у вас не было символов отладки для установки glibc. Это действительно не загрязняет глобальное пространство имен. (И, конечно, ваш 'buf' тоже не был глобальным символом).Вот почему могут быть два символа с разными адресами без получения ошибки связи. –

+0

И почему gdb выбрал отображение buf из libc, а не из asm-программы? И как преднамеренно просматривать содержимое buf и программы buc libc? Я имею в виду, как отличить их в командах gdb. –

Смежные вопросы