Что требуется для использования LODSB в сборке?
Какой минимальный набор шагов необходим для использования LODSB для загрузки относительного адреса в строку в моем коде?
У меня есть следующая тестовая программа, которую я использую PXE для загрузки. Я загружаю его двумя способами: через pxelinux.0 и напрямую. Если я загружаю его напрямую, моя программа печатает обе строки. Если я загружаюсь через pxelinux.0, он печатает только первую строку.
Зачем?
Ответ: Код в порядке, неправильный начальный адрес. Увидеть ниже.
Рабочая техника (для обоих):
- Установите флаг направления на приращение,
cld
- Задавать
ds
вcs
- Поместите адрес (с начала) строки в
si
- Добавьте начальное смещение к
si
Неработающая техника (только для pxelinux):
- Рассчитать новый адрес сегмента на основе
(((cs << 4) + offset) >> 4)
- Задавать
ds
к этому. (либо A000, либо 07C0)
текст здесь, чтобы исправить ошибку в уценке
// Note: If you try this code, don't forget to set
// the "#if 0" below appropriately!
.text
.globl start, _start
start:
_start:
_start1:
.code16
jmp real_start
. = _start1 + 0x1fe
.byte 0x55, 0xAA
// Next sector
. = _start1 + 0x200
jmp real_start
test1_str:
.asciz "\r\nTest: 9020:fe00"
test2_str:
.asciz "\r\nTest: a000:0000"
real_start:
cld // Make sure %si gets incremented.
#if 0
// When loaded by pxelinux, we're here:
// 9020:fe00 ==> a000:0000
// This works.
movw $0x9020, %bx
movw %bx, %ds
movw $(test1_str - _start1), %si
addw $0xfe00, %si
call print_message
// This does not.
movw $0xA000, %bx
movw %bx, %ds
movw $(test2_str - _start1), %si
call print_message
#else
// If we are loaded directly without pxelinux, we're here:
// 0000:7c00 ==> 07c0:0000
// This works.
movw $0x0000, %bx
movw %bx, %ds
movw $(test1_str - _start1), %si
addw $0x7c00, %si
call print_message
// This does, too.
movw $0x07c0, %bx
movw %bx, %ds
movw $(test2_str - _start1), %si
call print_message
#endif
// Hang the computer
sti
1:
jmp 1b
// Prints string DS:SI (modifies AX BX SI)
print_message:
pushw %ax
jmp 2f
3:
movb $0x0e, %ah /* print char in AL */
int $0x10 /* via TTY mode */
2:
lodsb (%si), %al /* get token */
cmpb $0, %al /* end of string? */
jne 3b
popw %ax
ret
.balign 0x200
Вот компиляция:
/usr/bin/ccache gcc -Os -fno-stack-protector -fno-builtin -nostdinc -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1 -DSUPPORT_GRAPHICS=1 -DHAVE_CONFIG_H -I. -Wall -ggdb3 -Wmissing-prototypes -Wunused -Wshadow -Wpointer-arith -falign-jumps=1 -falign-loops=1 -falign-functions=1 -Wundef -g -c -o ds_teststart_exec-ds_teststart.o ds_test.S
/usr/bin/ccache gcc -g -o ds_teststart.exec -nostdlib -Wl,-N -Wl,-Ttext -Wl,8000 ds_teststart_exec-ds_teststart.o
objcopy -O binary ds_teststart.exec ds_teststart
2 ответа
Первая проблема:
9020: FE00 ==> 9000: 0000, а не A000:0000
Я использовал некоторый код из grldrstart.S, который делает этот расчет. В рутине grldrstart.S есть ошибка. Он берет смещение FE00 и сдвигает его вправо на 4 бита, но делает это без сохранения знака; FE00 - отрицательное число. Так что вместо:
shrw $4, %bx
это должно было быть
sarw $4, %bx // Preserves sign!!
90200 + FE00 = 90200 - 200 = 90000
Вопрос ответ:
Чтобы использовать LODSB, вы должны:
- задавать
ds
правильно (и использовать правильную математику) - правильно установите флаг направления, используя
cld
или жеstd
для увеличения и уменьшения - задавать
si
к смещению к вашему исходному буферу. - прочитанный эффективный адрес будет
(ds << 4) + si