Таблица размещения файлов FAT

Первый сектор (с номером 0) диска — это загрузочный сектор. Его первые байты содержат следующую информацию:
byte
0-2 Переход на загрузочную программу
3-10 Имя в ASCII формате или что-нибудь еще
11-12 Байт на сектор
13 Секторов на кластер
14-15 Секторов в загрузочной записи =B
16 Количество копий FAT
17-18 Количество каталогов в корне диска
19-20 Секторов на диск
21 Тип диска =xx
22-23 Секторов на FAT =F
и т.д.
Первая таблица FAT начинается с B. Ее копия располагается в секторе B+F etc.
Можно детально рассмотреть FAT используя утилиту DEBUG. Не вносите изменений в таблицу FAT на жестком диске, если вы не уверены, что вы делаете.
Первая запись таблицы FAT выглядит так:

12 bit FAT: xx 0FFh 0FFh
16 bit FAT: xx 0FFh 0FFh 0FFh
xx — тип диска.
Затем, с кластера 2 начинаются элементы таблицы. Возможные значения перечислены в следующей таблице:
12-бит.FAT 16-бит. FAT
000h 0000h пусто
002h-0FEFh 0002h-0FFEFh использовано кластеров.
Значение-указатель на следующую запись в цепочке.
0FF0h-0FF6h 0FFF0h-0FFF6h зарезервировано
0FF7h 0FFF7h bad
0FF8h-0FFFh 0FFF8-0FFFFh последний кластер в цепочке
Вы можете читать сектора, используя прерывание 25h. Отметим, что это прерывание сохраняет флаги в стеке, так что после выполнения прерывания они должны быть восстановлены

Запуск дочерней программы
DOS выделяет всю доступную память текущей программе, независимо от того, какой объем реально необходим. Поэтому вы должны освободить часть памяти для того, чтобы загрузить и выполнить дочернюю программу. Это выполняется процедурой Setmem. Каждый параграф занимает 16 байт. Пространство, необходимое текущей программе вычисляется как размер в параграфах = Lseg — Psp + 1
где Lseg — сегмент, расположенный после последнего байта программы, а Psp — сегмент, в котором расположен psp программы.

Setmem proc
;Выделяет AX параграфов памяти текущей программе
:и очищает всю остальную память.
;Входные данные: количество выделяемых параграфов в AX
;Выходные данные: число реально выделенных параграфов в AX
mov BX,AX ;объем выделяемой памяти в 16-битных параграфах
mov AH,4Ah
int 21h ;ES должен указыват на сегмент PSP программы
mov AX,BX ;число выделенных параграфов
ret
Setmem endp
Следующий фрагмент кода запускает программу CHILD.COM с параметром /HELP.

;сегмент данныхt:
ChildName db ‘CHILD.COM’,0 ;имя файла в виде строки ASCIIZ

; сегмент кода:
mov AX,CS
mov SegCmdLine,AX
mov SegFCB1,AX
mov SegFCB2,AX
push DS ;сохраняем регистры
push ES
mov CS:Shell_SS,SS ;сохраняем только регистр CS
mov CS:Shell_SP,SP
;exec-function
mov DX,offset ChildName ;DS:DX — указатель на строку, содержащую имя файла
mov AX,CS
mov ES,AX
mov BX,offset CS:Parm_Table ;таблица параметров ES:BX
mov AX,4B00h ;загрузить и выполнить программу
int 21h
cli ;запрещаем прерывания
mov SS,CS:Shell_SS ;восстанавливаем регистры
mov SP,CS:Shell_SP
sti ;разрешаем прерывания
pop ES
pop DS
cld ;флаг направления (direction flag) = 0
jc ThereWasError ;ошибка

; эти данные должны быть определены в сегменте кода
CmdLineTail db 6,’ /HELP’,13 ;6 — число символов
even ;faster this way
Shell_SS dw 0 ;указатель стека
Shell_SP dw 0
Parm_Table dw 0 ;наследуем переменные окружения родительской программы
dw offset CmdLineTail
SegCmdLine dw 0 ;сюда будет записан CS
dw 5Ch ;блок управления файлом (FCB) #1
SegFCB1 dw 0 ;сюда будет записан CS
dw 6Ch ;блок управления файлом (FCB) #2
SegFCB2 dw 0 ;сюда будет записан CS

Реклама

Линейные преобразования в системах с фиксированной точкой

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

Числа предствалены в 32-битном формате с фиксированной точкой. Старшее слово содержит целую часть числа, а младшее слово — дробную часть. Предполагается, что используются только положительные числа.

Код использует 32-битные инструкции, но может быть откомпилирован и 16-битным компилятором.

; данные
ConvFactor dw 26214 ;младший байт коэффициента преобразования 25.4
dw 25 ;старший байт
Inches dw 32768 ;младший байт представления 12.5 дюймов
dw 12 ;старший байт
mMeters dw ? ;младший байт результата в мм
dw ? ;старший байт
; код
db 66h
mov AX,Inches ;mov EAX,dword ptr ConvFactor
db 66h
mul ConvFactor ;результат в EDX:EAX
mov CL,16
db 66h
shr AX,CL ;shr EAX,16
mov mMeters,AX ;младший байт результата
mov mMeters+2,DX ;старший байт

Установка видеорежимов VGA

Видеорежимы, поддерживаемые BIOS’ом адаптеров VGA BIOS:
Экран
Режим Текст Графика Цвета Размер Адрес

0 CGA 25*40 only text 16 B&W 2000 0B800h
1 CGA 25*40 only text 16 2000 0B800h
2 CGA 25*80 only text 16 B&W 4000 0B800h
3 CGA 25*80 only text 16 4000 0B800h
4 CGA 25*40 320*200 4 16000 0B800h
5 CGA 25*40 320*200 2 B&W 8000 0B800h
6 CGA 25*80 640*200 2 16000 0B800h
7 MDA 25*80 only text 2 4000
0Dh EGA 25*40 320*200 16 32000 0A000h
0Eh EGA 25*80 640*200 16 64000 0A000h
0Fh EGA 25*80 640*350 2 28000 0A000h
10h EGA 25*80 640*350 16 112000 0A000h
11h VGA 30*80 640*480 2 38400 0A000h
12h VGA 30*80 640*480 16 153600 0A000h
13h VGA 25*40 320*200 256 64000 0A000h
Требуемый видеорежим устанавливается вызовом функции BIOS

mov AH,0 ;POW39
mov AL,ScreenModeNumber
int 10h

Этот фрагмент также очищает экран. Содержимое AX не сохраняется. Стандартный BIOS не возвращает никакой информации, сигнализирующей об ошибке. В подерживаемых режимах можно читать и писать в видеопамять путем вызовов соответствующих функций (функции 8,9,0Ch,0Dh). Нормальный текстовый режим DOS — это режим 3.

Следующий фрагмент загружает набор символов из ROM в RAM и соответственно корректирует высоту отображения символов.

mov AH,11h ;изменить используемый набор символов и корректировать высоту их отображения
;mov AL,11h ;выбрать набор символов 8*14, 28 строк в режиме VGA
;mov AL,12h ;выбрать набор символов 8*8, 50 строк
mov AL,14h ;выбрать набор символов 8*16, 25 строк
mov BX,0 ;банк памяти генератора символов
int 10h

Asm: Определяем тип процессора

Следующая процедура WhatCPU определяет тип процессора, установленного в системе. Результат возвращается в регистре AX. Процедура может быть откомпилирована и 16-битным компилятором, несмотря на то, что в ней используются 32-битные инструкции для определения различия между 386, 486 и Pentium.

WhatCPU proc ;POW38
;Результат в AX
;0: i88,i86, 1: i186, 2: i286, 3: i386, 4: i486, 5: Pentium
pushf ;сохраняем флаги
mov DX,0F000h
sub AX,AX
push AX ;записываем 0 в верхушку стека
popf ;восстанавливаем регистр флагов из стека
pushf ;записываем флаги в стек
pop AX
popf ;восстанавливаем флаги
and AX,DX ;выделяем четыре старших байта
cmp AX,DX ;они равны 1 ?
jne CPU_ei8088
mov AX,0 ;результат 0 (8088 или 8086)
ret
CPU_ei8088:
push SP
pop BX
cmp BX,SP ;изменяется ли указатель стека перед записыванием в него?
je CPU_ei186
mov AX,1 ;результат 1 (80186)
ret
CPU_ei186:
pushf ;сохраняем флаги
mov AX,DX ;0F000h
push AX
popf
pushf
pop AX
popf ;оригинальные флаги
and AX,DX
jne CPU_ei286
mov AX,2 ;результат 2 (80286)
ret
CPU_ei286:
db 66h
pushf ;pushfd
db 66h
pushf ;pushfd
db 66h
pop AX ;pop EAX
db 66h
or AX,0000h
db 04h,00h ;или EAX,00040000h
db 66h
push AX ;push EAX
db 66h
popf ;popfd
db 66h
pushf ;pushfd
db 66h
pop AX ;pop EAX
db 66h
popf ;popfd
db 66h
test AX,0000h
db 04h,00h ;test EAX,00040000h
jnz CPU_ei386
db 66h
mov AX,3 ;результат AX=00000003h (80386)
db 0h,0h
ret
CPU_ei386:
db 66h
pushf ;pushfd
db 66h
pushf ;pushfd
db 66h
pop AX ;pop EAX
db 66h
mov BX,AX ;mov EBX,EAX
db 66h
xor AX,0000h
db 20h,00h ;xor EAX,00200000h
db 66h
push AX ;push EAX
db 66h
popf ;popfd
db 66h
pushf ;pushfd
db 66h
pop AX ;pop EAX
db 66h
popf ;popfd
db 66h
and AX,0000h
db 20h,00h ;and EAX,00200000h
db 66h
and BX,0000h
db 20h,00h ;and EBX,00200000h
db 66h
cmp AX,BX ;cmp EAX,EBX
jne CPU_ei486
db 66h
mov AX,4 ;результат EAX=00000004h (80486)
db 0h,0h
db 66h ;обнуление 32 битных регистров
xor BX,BX ;xor EBX,EBX
ret
CPU_ei486: ;Pentium
db 66h
mov AX,5 ;результат EAX=00000005h (Pentium)
db 0h,0h
db 66h
xor BX,BX ;xor EBX,EBX
ret
WhatCPU endp

Asm: Чтение значения счетчика времени

В памяти по адресу 40:6C расположено двойное слово, которое увеличивается на единицу приблизительно 18.2 раза в секунду. Системное время можно получить, считывая это слово. Младший байт может быть использован для многих «временных» задач, в т.ч. в качестве исходного значения для генератора псевдослучайных чисел (а в некторых случаях и заменить его).

GetTicks proc ;POW37
; Входные данные: нет
; Выходные данные: Младший байт счетчика времени в AX
; Регистры не сохраняются.
mov BX,ES ;Сохраняем адрес дополнительного сегмента
mov AX,40h ;сегмент данных BIOS
mov ES,AX
mov AX,ES:[6Ch] ;читаем счетчик
mov ES,BX ;восстанавливаем регистр ES
ret
GetTicks endp

Перевод чисел в двоичную форму (в виде строки)

Данная процедура конвертирует 16-битное слово в строку ASCIIZ, т.е. число 7 преобразовывается в строку 0000000000000111. Лидирующие нули включаются в строку. Строка ASCIIZ — это набор символов, завершающихся 0.

NmbrToBi$ proc ;POW36
;Входные данные: AX — смещение строки, BX — число, которое необходимо преобразовать
;Выходные данные: Строка ASCIIZ. Регистры не сохраняются.
mov DI,AX ;смещение строки
mov DX,8000h ;проверочное слово, 1 в позиции 15
mov CX,16 ;обрабатываем 16 бит
NumberTo_B0:
mov AL,48 ;символ ‘0’
test BX,DX ;бит равен 1?
jz NumberTo_B
inc AL ;символ ‘1’
NumberTo_B:
stosb ;записываем в строку ‘1’ или ‘0’
shr DX,1 ;сдвигаем тестовый бит вправо
loop NumberTo_B0
mov [DI],DL ;завершаем строку 0
ret
NmbrToBi$ endp

Процедура считывает строку с клавиатуры

KbdInput$ proc ;POW35
; Входные данные: смещение строки в AX
; Выходные данные: строка ASCIIZ, прочитанная с клавиатуры. Регистры не сохраняются.
mov DI,AX ;смещение строки
mov DX,AX ;смещение буфера
mov CX,255 ;максимальное количество читаемых символов
mov BX,0 ;файловый хэндл клавиатуры
mov AH,3Fh ;читаем из файла (фактически — с клавиатуры)
int 21h
jc Input$_error ;если ошибка
dec AX ;убираем символ RETURN
add DI,AX ;смещение байта, расположенного в конце строки
Input$_error:
mov [DI],BL ;завершаем строку, записывая 0 в конец строки

Задание выполняется на Visual C++ 2003 — 2008 с использованием assembler вставок. В этом задании необходимо выполнить соответствующие преобразования над строкой или строками.

/*
Задание выполняется на Visual C++ 2003 — 2008 с использованием
ассемблерных вставок. В этом задании необходимо выполнить соответствующие
преобразования над строкой или строками. Решение задачи необходимо оформить
в виде одной или несколько подпрограмм, содержащих ассемблерные вставки. Как
правило, в каждом задании по одной или двум входным строкам надо
получить выходную строку, удовлетворяющую определенным условиям, причем
под выходную строку необходимо выделить память и сделать это надо внутри
ассемблерной вставки. Кроме того, программа должна иметь «дружелюбный»
интерфейс (например, предлагать выполнить повторное тестирование). Ввод
данных из файла не требуется, хотя приветствуется. Ввод/вывод с
консоли выполнять с помощью функций printf и scanf, вызов которых
тоже должен происходить внутри ассемблерных вставок.
Указать те символы, которые есть и в первой и во второй строке.
*/

#include
#include

void main()
{
setlocale(0,»rus»);
const int N = 255;
char* res;
char* dys1 = «введите первую строку\n»;
char* dys2 = «\nвведите вторую строку\n»;
char* dys3 =»\nЕще? Enter — да, ESC — выход\n»;
char* err = «\nпамяти не дали»;
char* p = «pause»;
char* clear = «cls»;
char* ns = «Данные строки не имеют общих символов»;
char* str1;
char* str2;
__asm
{
// выделение памяти и считывание первой строки
BEGIN: ; главный цикл

mov eax,clear
push eax
call dword ptr system
add esp,4
mov eax,dys1 ;
push eax
call dword ptr printf ; вывели dys1
add esp,4 ; почистили стек

mov eax,N ; положили в eax размер строки
push eax ; положили размер в стек
call dword ptr malloc ; выделяем память под первую строку
add esp,4 ; чистим стек
cmp eax,0 ; проверяем, выделилась ли память
je MEMORY_ER ; В случае не выделения памяти сообщаем об ошибке
mov str1,eax ; если памяти дали, то записываем адрес первой строки
push eax ; опять положили в стек адрес первой строки
call dword ptr gets ; считали строку
add esp,4 ; почистили стек

mov eax,dys2
push eax
call dword ptr printf
add esp,4

mov eax,N ; положили в eax размер строки
push eax ; положили размер в стек
call dword ptr malloc ; выделяем память под вторую строку
add esp,4 ; чистим стек
cmp eax,0 ; проверяем, выделилась ли память
je MEMORY_ER ; В случае не выделения памяти сообщаем об ошибке
mov str2,eax ; если памяти дали, то записываем адрес первой строки
push eax ; опять положили в стек адрес первой строки
call dword ptr gets ; считали строку
add esp,4 ; почистили стек
mov edx,str2 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память
mov ebx,str1 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память
// в еbx — адрес первой строки
// в edx — адрес второй строки
// поиск
mov edx,str2 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память
mov ebx,str1 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память

xor eax,eax ; обнуляем eax
// теперь нам надо посчитать количество совпавших элементов
xor edi,edi ; в edi количество совпавших элементов

START: ; внешний цикл

xor esi,esi ; esi — текущий счетчик
mov cl,[ebx][eax] ; положили в cl первый символ первой строки
inc eax ; увеличили счетчик
cmp cl,0 ; проверка конца строки
je NEW_RES ; ушли на выделение памяти под результат

START2:
mov ch,[edx][esi] ; положили в ch следующий символ
cmp ch,0 ; проверка конца строки
je END ; ушли в обнуление текущего счетчика

cmp cl,ch ; сравнили символы
je FOUND ; если символы совпали — говорим нашли
inc esi ; увеличили текущий счетчик
jmp START2

END:
jmp START ; возвращаемся в главный цикл

FOUND:
inc edi ; увеличили счетчик совпавших символов
jmp START ; ушли в главный цикл

NEW_RES:
cmp edi,0
je NOT_SOVP
inc edi ; увеличили размер результатата под 0 символ
push edi ; положили в eax размер результата
call dword ptr malloc ; выделили память под результат
add esp,4 ; почистили стек
cmp eax,0 ; проверили выделение памяти
je MEMORY_ER
mov res,eax ; записали адрес результата

jmp RES
NOT_SOVP:
mov eax,ns
push eax
call dword ptr printf
add esp,4
mov eax,res
xor eax,eax
xchg res,eax
jmp REPEAT

RES:

mov edx,str2 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память
mov ebx,str1 ; запомнили адрес первой строки, чтоб лишний раз не лазить в память

// в еbx — адрес первой строки
// в edx — адрес второй строки
xor ecx,ecx
xor eax,eax
xor edi,edi

START3: ; внешний цикл

xor esi,esi ; esi — текущий индекс второй строки
mov cl,[ebx][eax] ; положили в cl первый символ первой строки
inc eax ; увеличили счетчик
cmp cl,0 ; проверка конца строки
je PRINT_RES ; ушли на выделение памяти под результат

START4:
mov ch,[edx][esi] ; положили в ch следующий символ
cmp ch,0 ; проверка конца строки
je END1 ; ушли в обнуление текущего счетчика

cmp cl,ch ; сравнили символы
je FOUND1 ; если символы совпали — говорим нашли
inc esi ; увеличили текущий счетчик
jmp START4

END1:
jmp START3 ; возвращаемся в главный цикл

FOUND1:

xchg esi,res
//push esi
//mov esi,res
mov [esi+edi], cl ; на место res[edi] кладём совпавший символ
xchg esi,res
//pop esi
inc edi ; увеличили счетчик совпавших символов
jmp START3 ; ушли в главный цикл

PRINT_RES:
//inc edi
//xor eax,eax
mov esi,res
xor cl,cl
mov [esi+edi],cl

push esi
call dword ptr printf
add esp,4

REPEAT:
mov eax,str1
push eax
call dword ptr free
add esp,4
mov eax,str2
push eax
call dword ptr free
add esp,4
mov eax,res

cmp eax,0

je NEXT
push eax
call dword ptr free
add esp,4

NEXT:

mov eax,dys3
push eax
call dword ptr printf
add esp,4

call dword ptr getch ; смотрим, что нажали
cmp eax,27
je EXIT
cmp eax,13
je BEGIN
jmp BEGIN

MEMORY_ER:
mov eax,err
push eax
call dword ptr printf
add esp,4
mov eax,p
push eax
call dword ptr system
add esp,4
jmp REPEAT
EXIT:
}

}

Ассемблер сопроцессор: Вычислить 4 значения функции: Y = 3 * log2(x2+1), x изменяется от 0,2 с шагом 0,3.

Вычислить 4 значения функции: Y = 3 * log2(x2+1), x изменяется от 0,2 с шагом 0,3.

3.1 Текст программы

.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0.2 ; сохранение в 32-разрядном амбарчике памяти переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 0.3
umnoj dd 3
const dd 4
mem dw ?
_MASK equ 0C00h
ifmt db «Y = %d»,0
st1 db «Вывод функции»,0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
finit ; инициализания сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,4

fld _x
fld _x
m1:
fild umnoj
fld st(1)
fmulp st(2),st(0)
fyl2x
fld hod
fadd st(2),st(0)

fistp dword ptr [edi] dec const
jz m2
fistp dword ptr [esi] fld st(0)
mov eax[esi] add edi,4
add esi,4
loop m1
m2:

invoke FpuFLtoA, 0, 10, ADDR st2, SRC1_FPU or SRC2_DIMM
invoke MessageBox, NULL, addr st2, addr st1, MB_OK
invoke ExitProcess, NULL ; возвращение управления ОС Windows
; но освобождение ресурсов

end _start ; директива окончания программы с именем start

Ассемблер сопроцессор: Определить номер (х) элемента функции: xn = 3х + 5, при котором сумма элементов превысит 12 000. Результат разместить в памяти и вывести соответствующие сообщения.

Определить номер (х) элемента функции: xn = 3х + 5, при котором сумма элементов превысит 12 000. Результат разместить в памяти и вывести соответствующие сообщения.

2.1 Текст программы

.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0 ; сохранение переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 1
krok dd 3
plus dd 5
mem dw ?
_MASK equ 0C00h
limit dd 12000
ifmt db «№ = %d»,0
st1 db «Вывод номера елемента»,0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
mov edx,limit
finit ; инициализация сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,6
m1:
inc _x
fild _x
fild krok
fyl2x
fld st(0)
frndint
fsub st(1),st(0)
frndint
f2xm1
fiadd hod
fldz
fadd st(0),st(2)
f2xm1
fiadd hod
fmul st(0),st(1)
fiadd plus
fistp dword ptr [edi] fistp dword ptr [esi] fistp dword ptr [esi] mov eax[edi] add ebx,eax
add edi,4
add esi,4
cmp edx,ebx
jns m1

mov eax,_x

invoke wsprintf \
ADDR st2 \
ADDR ifmt \
eax
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; зак?нчення программы