Адрес массива - * & amp; массив C ++ [дубликат]

Вы не предоставляете минимальный полный проверяемый пример, показывающий загрузчик и как его получить в VDI. Но, как минимум, вам нужно разместить 0xAA55 в последних двух байтах основной загрузочной записи. В приведенном ниже примере создается простой загрузчик; создает исходное изображение 2MiB; помещает загрузчик в необработанное изображение; и преобразует необработанное изображение в VDI.

boot.asm:

BITS 16
ORG 0x7C00

    xor ax, ax
    mov ds, ax
    mov ss, ax       ; Stack below bootloader
    mov sp, 0x7c00

    mov ax, 0xb800   ; Video segment b800
    mov es, ax

    ; Print Hello with white on light magenta
    mov word [es:0x0], 0x57 << 8 | 'H'
    mov word [es:0x2], 0x57 << 8 | 'e'
    mov word [es:0x4], 0x57 << 8 | 'l'
    mov word [es:0x6], 0x57 << 8 | 'l'
    mov word [es:0x8], 0x57 << 8 | 'o'

    ; End with infinite loop
    cli
endloop:
    hlt
    jmp endloop

; Fill out to 510 bytes and add boot signature
times 510 - ($ - $$) db 0
dw 0xAA55            ; add boot signature at the end of bootloader

Затем я использую эту команду для создания файла загрузчика boot.bin:

nasm -f bin boot.asm -o boot.bin

Создайте файл образа диска 2MiB 1.raw:

dd if=/dev/zero of=1.raw bs=1024 count=2048

Поместите загрузчик boot.bin в начало файла 1.raw, не обрезая остальную часть файла:

dd if=boot.bin of=1.raw conv=notrunc

Создайте изображение VDI с именем 1.vdi из 1.raw:

rm -f 1.vdi
VBoxManage convertfromraw 1.raw 1.vdi --format VDI

При добавлении в виртуальную машину в VirtualBox я получаю это на дисплее:


Ваш файл VDI

В прилагаемом файле изображения 1.vdi я заметил это, когда сделал hexdump:

00200000  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000

blockquote>

Этот вывод подсказывает мне, что вы отменили байты начальной загрузки в вашем файле. Он должен быть 0x55, за которым следует 0xaa. 0xaa55 как WORD хранится с байтами, которые были отменены.

Допустимый загрузочный носитель может быть больше, чем правильное получение начальной подписи. Некоторые BIOS могут искать определенные инструкции в первых байтах, которые обычно находятся в загрузчиках. Несоблюдение таких инструкций (примеры часто включают такие вещи, как JMP , XOR , CLI , MOV ) могут привести к его думать, что это не допустимый загрузочный носитель.

Один из способов проверить, достаточно ли 0xAA55 в конце, я использовал hexedit и изменил ваш файл 1.vdi, чтобы выглядеть так:

00200000  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
00200010  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002001f0  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 55 aa <-- Corrected signature
                                                               at 1fe & 1ff
00200200  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000
blockquote>

Выполнение этого изменения не помогло. Затем я использовал hexedit и поместил код операции CLI (0xFA) в качестве первого байта сектора. Результирующий файл теперь выглядит следующим образом:

           v-- CLI instruction
00200000  fa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
00200010  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002001f0  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 55 aa
00200200  aa 55 aa 55 aa 55 aa 55  aa 55 aa 55 aa 55 aa 55
*
002004c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
*
00300000
blockquote>

Я поместил fa в качестве первого байта в загрузчик. Теперь, когда я использую ваше изображение, ошибка Не найден загрузочный носитель! Системная остановка больше не отображается. Это говорит о том, что VirtualBox ищет больше, чем загрузочную подпись, и делает какую-то проверку здравомыслия, чтобы определить, является ли начало загрузчика исполняемыми инструкциями. Это не редкость для BIOS. Некоторые могут сделать такую ​​проверку, а некоторые - нет. В это время я не просматривал исходный код VirtualBox, чтобы определить точные проверки, которые он выполняет, чтобы определить его.

22
задан Kevin Reid 4 June 2013 в 15:32
поделиться

3 ответа

Когда t используется само по себе в выражении, происходит преобразование между массивами и указателями, это создает указатель на первый элемент массива.

Когда t является используется как аргумент оператора &, такое преобразование не происходит. & затем явно принимает адрес t (массив). &t является указателем на массив в целом.

Первый элемент массива находится в той же позиции в памяти, что и начало всего массива, и поэтому эти два указателя имеют одинаковое значение .

24
ответ дан Mankarse 22 August 2018 в 17:12
поделиться
  • 1
    Благодаря! Я предполагаю, что это было неявное преобразование между строками и указателями, которое дало мне неправильное мышление u, являющееся указателем. – quuxbazer 7 December 2011 в 11:33
  • 2
    @quuxbazer: u есть указатель. t является массивом. int * u = t применяет преобразование массива к указателю в t и инициализирует u с результатом. – Mankarse 7 December 2011 в 11:45
  • 3
    -1 это неправильное описание для c ++ – Johannes Schaub - litb 7 December 2011 в 12:38
  • 4
    @ JohannesSchaub-litb: В этом случае меня будет интересовать правильное описание. – Mankarse 7 December 2011 в 12:43
  • 5
    (e ? a : n) не создает указатель, если, например, обе стороны имеют один и тот же тип массива. – Johannes Schaub - litb 7 December 2011 в 12:46

Фактическим типом t является int[10], поэтому &t является адресом массива. Кроме того, int[] неявно преобразуется в int*, поэтому t преобразует в адрес массива как первый элемент массива.

3
ответ дан Abyx 22 August 2018 в 17:12
поделиться
  • 1
    Нет, он преобразуется в адрес первого элемента. Абсолютные места памяти одинаковы, но типы совершенно разные. – Ben Voigt 4 June 2013 в 16:10
  • 2
    @BenVoigt, да, спасибо. – Abyx 5 June 2013 в 09:04

Нет переменной под названием t, так как вы не можете ее изменить. Имя t просто ссылается на адрес первого элемента (а также имеет связанный с ним размер). Таким образом, обращение адреса адреса на самом деле не имеет смысла, а C «сворачивает» его на просто адрес.

То же самое происходит для случая функций:

int foo(void)
{
  return 12;
}

printf("%p and %p\n", (void *) foo, (void *) &foo);

Это должно печатать одно и то же, поскольку нет переменной, удерживающей адрес foo, адрес которого по очереди можно взять.

-2
ответ дан unwind 22 August 2018 в 17:12
поделиться
  • 1
    Это C ++, и есть переменная, называемая t. Вы можете передать его функции, которая принимает аргумент с типом int(&)[10]. – Abyx 7 December 2011 в 11:10
  • 2
    -1 "Нет переменной, называемой t, поскольку вы не можете ее изменить. & Quot; это неверно. Объект, который указан в объявлении, называется переменной. Посмотрите стандарт. – Cheers and hth. - Alf 7 December 2011 в 11:12
Другие вопросы по тегам:

Похожие вопросы: