Что делает resb NASM в двоичном формате вывода?

Я видел кусок кода NASM, который использует resb, Однако этот код работает в операционной системе реального режима, а выходной формат - плоский двоичный. NASM не выдает ошибку при этом, но после разбора выходного файла я все еще не мог найти то, что на самом деле происходит.

bits 16
org 0x8000

start:
    mov ax, msg
    call os_input_string
    mov si, msg
    call os_print_string
    ret

section .bss
msg: resb 256

Вот несколько вариантов, о которых я подумал:

  • resb просто выделяет некоторое неиспользуемое пространство в конце двоичного файла
  • это на самом деле не работает, и все взрывается.

3 ответа

Решение

Когда NASM генерирует двоичный файл -f bin это следует некоторым основным правилам о разделах. Руководство NASM говорит это:

7.1.3 Многосекционная поддержка формата bin

[Надрез]

  • Раздел.bss будет помещен после последнего раздела progbits, если не было указано start=, vstart=, follow = или vfollows=.

progbits флаг, обозначающий раздел, который будет физически отображаться в файле (по умолчанию .text а также .data секции). .bss по умолчанию nobits Это означает, что данные, зарезервированные в этом разделе, физически не отображаются в файле, но любые адреса меток в nobits помеченный раздел будет разрешен (по умолчанию) в память сразу после последнего progbits (.text а также .data и т.д.) раздел. Область BSS в двоичном файле не инициализируется нулем. Это будет то, что происходит в памяти, так что рассмотрите область, чтобы содержать мусор. Если вам нужна двоичная программа для инициализации этой области на ноль, вам придется сделать это самостоятельно, как только ваша программа начнет выполняться.

В вашем вопросе есть намеки на то, что вы создаете второй этап загрузчика. Я приведу пример кода, который инициализирует область BSS нулями. Этот код предполагает, что второй этап был загружен в 0x0000:0x8000:

bits 16
org 0x8000

section .text
start:
    ; Initialize the entire BSS area to zero
    ; Assume we are the second stage of a bootloader at 0x0000:0x8000
    mov cx, _bss_end-_bss_start    ; Length of region in CX
    xor ax, ax                     ; AX=0 (also used for rep stos)
    mov es, ax
    mov ds, ax                     ; DS=ES=0x0000
    mov di, _bss_start             ; Offset of BSS region 
    rep stosb                      ; Set CX bytes of data at ES:[DI] to AL(0)

    mov ax, msg
    mov si, msg2

    ; Put second stage in halt state indefinitely.
    cli
.endloop:
    hlt
    jmp .endloop

section .bss
_bss_start:      ; Label for start of BSS
msg: resb 256
msg2: resb 10
_bss_end:        ; Label at end of BSS

Хотя память для BSS не является частью двоичного файла на диске, метки для данных в этой области преобразуются в реальные смещения. Вы можете пометить начало и конец области BSS, и в этом случае я использую _bss_start а также _bss_end, Эти метки используются для определения степени области BSS, чтобы ее можно было инициализировать нулем, когда наш код начинает выполняться.

Это все написано в руководстве, конечно. resb резервирует неинициализированное хранилище в .bss раздел. Более того, bin файлы имеют ограниченную поддержку разделов, в частности:

Разделы могут быть обозначены как прогбиты или нобиты. По умолчанию это progbits (кроме.bss, который по умолчанию равен nobits, конечно). Раздел.bss будет помещен после последнего раздела progbits, если не было указано start=, vstart=, follow = или vfollows=.

Таким образом, " resb просто выделяет некоторое неиспользуемое пространство в конце двоичного файла " - это, в основном, то, что происходит. Не уверен, почему вы не можете увидеть это из разбора выходного файла.

Поскольку раздел.bss никогда не содержит инициализированных данных (устанавливается как nobits), это не должно быть записано в файл. При использовании плоского двоичного формата NASM просто вычислит подходящий указатель для переменной и все.

Разбирая код, вы можете легко увидеть, что происходит. Я скомпилировал этот код:

bits 16
org 0x8000

start:
    mov ax, msg
    ret

section .bss
msg: resb 256

При запуске полученного двоичного файла через ndisasm:

00000000  B80480            mov ax,0x8004
00000003  C3                ret

Таким образом, вы можете ясно видеть, что NASM написал четыре байта кода и определил, что раздел.bss может быть помещен сразу после этого, начиная с позиции 0x8004. Таким образом, в двоичном файле ничего не выделяется, только указатели рассчитываются на основе требуемого распределения в.bss.

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