O código de inicialização do aplicativo se parece com isto:
CPU 8086
_start:
cld
mov ax, ds
dec ax
mov es, ax
mov ax, [es:3]
cmp ax, word (_endbss + 768) / 16
jae .mem
; Code would be here to emit an out of memory error
.mem:
mov ax, 4C00h
int 21h
section .bss
_bss:
big_array resb 16384
_endbss:
O que ele deveria estar fazendo? Verificando se realmente temos RAM suficiente para executar o programa ou não.
O que ele está realmente fazendo? Não está montando.
A ideia geral é que precisamos de muita RAM, então configuramos Código + BSS + Pilha no segmento inicial e o slab acima dele (que excederá 64K por si só, então não faz sentido colocá-lo abaixo da pilha...). Estou convencido de que o assembler deve ser capaz de fazer isso, mas não consigo descobrir o que digitar para que funcione.
Como faço para obter a expressão que seria (_endbss + 768) / 16
para montar a constante que definitivamente é? Eu realmente prefiro não ter que descobrir isso em tempo de execução.
Infelizmente, o NASM
-f bin
funciona principalmente como um simples linker embutido no NASM. Ele não substitui as regras usuais de que qualquer matemática em endereços de símbolos deve ser representável com entradas de realocação, e não é conhecido no momento da montagem (apenas no momento do link).Mas você provavelmente ainda precisa de seções separadas para que
resb
elas possam ser incluídas.bss
e não reunidas em bytes no arquivo de saída.Você pode somar os comprimentos das suas duas seções, partindo do princípio de que não há preenchimento para alinhamento entre as seções. (Você pode tornar isso uma realidade com
section .bss align=1
if esse não é o padrão, eu acho.) Então adicionamos um_endtext
rótulo após o último byte de.text
, e a instrução problemática se torna:Listagem (
nasm -l /dev/stdout -f bin foo.asm
) de um exemplo funcional:No arquivo de saída real
foo
,mov ax, _endbss
montado emb8 1c 40
(nãob8 00 40
como a listagem mostra como um espaço reservado), então1c 40
(little-endian) =0x401c
é a parte deslocada do endereço completo e é o que você queria_endbss
avaliar.A comparação imediata é little-endian,
31 04
que é0x0431
.Insira esse
_endbss
valor na sua expressão para verificar os resultados:(0x401c + 768) / 16
arredonda para baixo para 1073, que é0x431
o valor que minha expressão obteve paracmp
.Não testei exaustivamente com extras
times x db 1
em tamanhos .ext ou que não sejam potências de 2.bss
para garantir que não haja desvio de um em um corte entre o próximo tamanho ou corte para o próximo nível de preenchimento de alinhamento, se houver.