#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.