Вопрос GDB с программой на C

#assembly #gdb #x86-64 #x86

#сборка #gdb #x86-64 #x86

Вопрос:

Здесь я рассматриваю простую программу, написанную на C, которая сохраняет указатель char на строку с надписью «Привет, мир! n».

Вот выходные данные моей GDB… Я смущен несоответствием GDB и того, что прямо здесь:

 $ gcc -g pointer.c
$ gdb -q ./a.out
Reading symbols for shared libraries .. done
(gdb) list
1   #include <stdio.h>
2   #include <string.h>
3   
4   int main() {
5     char str[20];
6     char *pointer;
7   
8     strcpy(str, "Hello, world!n");
9     pointer = str;
10    printf("%s",pointer);
(gdb) 
11  }
(gdb) break 10
Breakpoint 1 at 0x100000ed1: file pointer.c, line 10.
(gdb) run
Starting program: /Users/___/a.out 
Reading symbols for shared libraries  . done

Breakpoint 1, main () at pointer.c:10
10    printf("%s",pointer);
(gdb) print pointer
$1 = 0x7fff5fbff950 "Hello, world!n"
(gdb) print amp;pointer
$2 = (char **) 0x7fff5fbff948
(gdb) x/s 0x7fff5fbff950
0x7fff5fbff950:  "Hello, world!n"
(gdb) x/16b 0x7fff5fbff950
0x7fff5fbff950:  "Hello, world!n"
0x7fff5fbff95f:  ""
0x7fff5fbff960:  "x??_?"
0x7fff5fbff967:  ""
0x7fff5fbff968:  "՝?Y4?K33???_?"
0x7fff5fbff977:  ""
0x7fff5fbff978:  "?16"
0x7fff5fbff97b:  ""
0x7fff5fbff97c:  "01"
0x7fff5fbff97e:  ""
0x7fff5fbff97f:  ""
0x7fff5fbff980:  ""
0x7fff5fbff981:  ""
0x7fff5fbff982:  ""
0x7fff5fbff983:  ""
0x7fff5fbff984:  ""
(gdb) x/x 0x7fff5fbff950
0x7fff5fbff950: 0x48
(gdb) x/x 0x7fff5fbff951
0x7fff5fbff951: 0x65
(gdb) x/s 0x7fff5fbff951
0x7fff5fbff951:  "ello, world!n"
(gdb) print amp;pointer
$3 = (char **) 0x7fff5fbff948
(gdb) x/x 0x7fff5fbff948
0x7fff5fbff948: 0x00007fff5fbff950
(gdb) x/x 0x7fff5fbff949
0x7fff5fbff949: 0x4800007fff5fbff9
(gdb) x/2x 0x00007fff5fbff950
0x7fff5fbff950: 0x77202c6f6c6c6548  0x00000a21646c726f
  

Мои вопросы:

Сколько байтов информации хранится в одном из этих местоположений в памяти? Когда я нахожусь по адресу 0x7fff5fbff950, содержимое отображается как 0x48 (ASCII ‘H’). Значит ли это, что на каждый адрес памяти хранится только байт информации? ОК. Давайте предположим, что это так. Затем я запускаю ту же команду «x / x» по адресу, указанному в print amp; pointer: 0x7fff5fbff948

Я получил значение 0x00007fff5fbff950, которое я распознаю (игнорируя начальные нули) как начало «Привет, мир!n «строка в памяти.

Теперь, как 0x00007fff5fbff948 может содержать 0x00007fff5fbff950 и при этом иметь только один байт памяти? Итак, я смотрю на 0x00007fff5fbff949 … и это снова говорит мне о том, что мы каждый раз смотрим только на байт, поскольку мы потеряли конечный 0x50 (я знаю, что с небольшим порядком окончания, поэтому, возможно, я формулирую это неправильно).

Теперь я действительно злюсь… Я пытаюсь выполнить x / 2x 0x7fff5fbff948, и меня атакуют двумя гигантскими шестнадцатеричными числами…

Итак, данные в памяти хранятся по одному байту за раз, и каким-то образом x / x иногда выдает мне один байт на память, а иногда и весь адрес? Как я могу контролировать то, что будет выводить отладчик? x / x следует проверить содержимое этого адреса и вывести в шестнадцатеричном формате. Я могу использовать x / b для одного байта, x / 2b для 2 байтов… но что означает x / 2x?

Извините за поток вопросов о сознании.. надеюсь, кто-нибудь сможет помочь мне прояснить это.

Ответ №1:

Память адресуема в байтах, что означает, что каждый байт имеет отдельный адрес. Тогда вы можете интерпретировать, скажем, пару байтов как 16-разрядное целое число, четыре байта как 32-разрядное целое число и т.д. Этот спецификатор формата позволяет вам делать именно это — печатать содержимое памяти в соответствии с вашей интерпретацией. Таким образом, x/2x 0x7fff5fbff948 будут выведены два целых числа размером с слово (здесь 64-разрядные), первое по адресу 0x7fff5fbff948 , а второе по адресу 0x7fff5fbff950 .

Комментарии:

1. Во-первых, спасибо за ваш ответ. Хорошо, но два 64-битных целых числа явно соответствуют двум 8-байтовым целым числам. Поскольку каждый байт имеет свой отдельный адрес, если я выполняю x / 2x и печатаю два 64-битных целых числа по адресам ____48 и ____50, это означает, что должно быть перекрытие с _____48 и _____50, и я не вижу никакого перекрытия в третьем байте из 48 и первом байте из 50 и далее. Можете ли вы помочь объяснить это?

2. Почему должно быть перекрытие? 0x50 - 0x48 = 8 , то есть восемь байтов.

3. 🙂 Спасибо. Глупая ошибка … забыл, что мы в базе 16.