Системне програмування та операційні системи
Зміст:
1. Робота в операційній системі Linux. Програмування в оболонці shell.
2. Операційна система Windows. Системне програмування в MASM.
3. Операційна система Windows. Системне програмування в MASM32 з використанням функцій API.
Робота в операційній системі Linux. Програмування в оболонці shell.
Найпростіші засоби SHELL
Командний мова shell (у перекладі - раковина, шкаралупа) фактично є мовою програмування дуже високого рівня. На цій мові користувач здійснює управління комп'ютером. Зазвичай, після входу в систему ви починаєте взаємодіяти з командною оболонкою. Ознакою того, що оболонка (shell) готова до прийому команд служить видається нею на екран промптер. У найпростішому випадку це один долар ("$").
shell - це одна з багатьох
команд UNIX. Тобто в набір команд
оболонки "shell" входить команда
"sh" - виклик інтерпретатора "shell".
Перший "shell" викликається автоматично
при вашому вході в систему
і видає на екран промтері.
Після цього ви можете
Так наприклад, якщо ви підготуєте
в редакторі файл "file_1":
echo Hello!
то це буде звичайний текстовий файл, що
містить команду "echo", яка при виконанні
видає все написане правіше від неї на
екран.
Оскільки UNIX - система
розрахована на багато
Стрижневим елементом мови shell
є команда.
Структура команд
Команди в shell зазвичай мають
наступний формат:
<Ім'я команди> <прапори> <аргумент
(и)>
Наприклад:
ls-ls / usr / bin
Де ls - ім'я команди видачі вмісту директорія,
-Ls - прапори ("-" - ознака прапорів,
l - довгий формат, s - об'ем файлів в блоках),
/ Usr / bin - директорій, для якого виконується
команда.
Ця команда видасть на екран у довгому
форматі вміст директорії / usr / bin, при цьому
додасть інформацію про розмір кожного
файлу в блоках.
На жаль, така структура команди витримується
далеко не завжди. Не завжди перед прапорами
ставиться мінус, не завжди прапори йдуть
одним словом. Є різноманітність і в поданні
аргументів. До числа команд, які мають
екзотичні формати, відносяться і такі
"ходові" команди, як сс - виклик компілятора
мови С, tar - робота з архівами, dd - копіювання
файлу з перетворенням, find - пошук файлів
і ряд інших.
Як правило, перше слово shell сприймає, як
команду. Тому в командному рядку
cat cat
перше слово буде розшифровано shell, як
команда (конкатенації), яка видасть на
екран файл з ім'ям "cat" (друге слово),
що знаходиться в поточному директорії.
Shell-змінні
Ім'я shell-змінної - послідовність, що розпочинається з букви, та вміщує цифри, знак підкреслювання.
Значення shell-змінної - рядок символів.
У shell всього два типи даних: рядок символів та текстовий файл.
Ім'я змінної аналогічно традиційному представленню про ідентифікатор, тобто ім'ям може бути послідовність букв, цифр та підкреслювань, розпочинається з букви або підкреслення.
Для присвоювання значення змінним може використовуватися оператор присвоювання "=".
var_1=13
var_2="OS Unix"
Змінна та її значення повинні бути записані без пробілів відносно символа "=".
Можливі й інші способи присвоювання значення shell-змінним. Так, наприклад: DAT=`date` приводить до того, що спочатку виконується команда "date" а результат її виконання, замість видачі на стандартний вихід, прописується у якості значення змінної, у даному випадку "DAT".
Можна надати значення змінної за допомогою команди "read", яка забезпечує прийом значення з клавіатури: read x.
Одна команда "read" може прочитати значення відразу для декількох змінних, по черзі. Якщо змінних більше, чим їх введено, то тим що залишилися змінним присвоюється порожній рядок, якщо введено більше, то зайві значення ігноруються.
Під час звернення до shell-змінної необхідно перед ім'ям ставити символ "\$", так відповідно команда echo $var_2; виведе на екран "OS Unix".
Екранування
Як засоби екранування використовуються подвійні лапки (""), одинарні лапки (' ') та бек-слеш (\).
Можна в одному рядку записувати декілька присвоювань.
x=22 y=33 z=$x
A="$x" B='$x' C=\$x
D="$x + $y + $z" E='$x + $y + $z' F=$x\ +\ $y\ +\ $z
Тоді
echo A = $A B = $B C = $C
echo D = $D E = $E F = $F
eval echo evaluated A = $A
eval echo evaluated B = $B
eval echo evaluated C = $C
виведуть на екран
A = 22 B = $x C = $x
D = 22 + 33 + 22 E = $x + $y + $z F = 22 + 33 + 22
evaluated A = 22
evaluated B = 22
evaluated C = 22
"eval" - команда, що виконує означення змінних в рядку, що є аргументом.
Бек-слеш не тільки екранує наступний за ним символ, що дозволяє використовувати спеціальні символи просто як символи, що представляють самих себе, він може екранувати сам себе. Цей символ також може створювати ефект продовження рядка. Ефект продовження командного рядка забезпечує також символ конвеєра - "|".
Програмні структури
Як і в будь-якій мові програмування у тексті мовою shell можуть бути коментарі. Для цього використовується символ "#". Усе, що знаходиться в рядку лівіше від даного символу, сприймається інтерпретатором як коментар.
Як і в будь-якій процедурній мові програмування, в мові shell є оператори. Ряд операторів дозволяє керувати послідовністю виконання команд. У таких операторах часто необхідна перевірка умови, яка визначає напрямок продовження обчислень.
Умовний оператор ("IF").
У загальному випадку оператор "if" має структуру:
if умова
then список
[elif умова
then список]
[else список]
fi
Оператор вибору ("CASE").
Оператор вибору "case" має структуру:
case рядок in
шаблон) список команд;;
шаблон) список команд;;
...
esac
"Рядок" (це може бути і один символ), що порівнюється із шаблоном. Потім "список команд" вибраного рядка.
Приклад:
echo -n " А какую оценку получил на экзамене?: "
read z
case $z in
5) echo Молодец ! ;;
4) echo Все равно молодец ! ;;
3) echo Все равно ! ;;
2) echo Все ! ;;
*) echo ! ;;
esac
Оператор циклу із перерахуванням ("FOR").
Оператор циклу "for" має структуру:
for ім'я [in список значень]
do
список команд
done
де "for" - це службове слово, що визначає тип циклу, "do" та "done" - це службові слова, що виділяють тіло циклу. Фрагмент "in список значень" може бути відсутнім.
Оператор циклу з істиною умовою ("WHILE").
Оператор циклу "'while' має структуру:
while умова
do
список команд
done
де "while" - службове слово, що визначає тип циклу з істиною умовою. Список команд у тілі циклу повторюється до тих пір, доки зберігається істинність умови (доки умови не дорівнює 0) або цикл буде перерваний командами "break", "continue" або "exit".
Оператор циклу з хибною умовою ("UNTIL").
Оператор циклу "until" має структуру:
until умова
do
список команд
done
де "until" - службове слово, що визначає тип циклу з хибною умовою. Список команд в тілі циклу повторюється стільки разів, скільки буде зберігатися хибність умови або цикл не буде перерваним спеціальними командами.
Відмінність від "while" полягає в тому, що умова циклу перевіряється на хибність, перевіряється після кожного виконання тіла циклу.
Пустий оператор.
Пустий оператор має формат:
Нічого не робить. Повертає значення "0". Наприклад, в конструкції "while :" або ставить у початок командного файлу, щоб гарантувати, що файл не буде прийнятий за виконавчий для "csh".
Завдання №1:
27. Дан текст, каждый символ которого может быть малой буквой, большой буквой, цифрой или одним из знаков “+”, “-”, “*”. Группой букв будем называть такую совокупность последовательно расположенных букв, которой непосредственно не предшествует и за которой непосредственно не следует буква. Аналогично определим группу цифр и группу знаков. Найти все такие группы букв, в которые буква “а” входит не менее 2-х раз.
Код програми:
#!/bin/bash
#1 #вивід інформації про
виконавця роботи та ввід
gdialog --title "Виконав" --msgbox "Башинський Олег БІТ-3-09"
gdialog --title "Вхідні дані" --inputbox "Введіть текст" 10 50 2> lab6text.txt
#ввід вхідних даних
if [ $? -ne 1 ];
#Рядок опрацьовується якщо ввід підтверджено («Ок»)
then
ptext=$(cat lab6text.txt)
#вхідний рядок
text=$ptext;
#його копія
n=${#ptext};
#кількість символів
i=0;
j=0;
m=0;
#2
while [ $i -le $n ];
#цикл по символах строки
do
k=${ptext:$i:1}
#вибір і-го символу в строці
case $k in
#перевірка чи належить символ до літер, і формування груп літер
1|2|2|3|4|5|6|7|8|9|0) grup=' '; m=$(($m+1));;
#якщо не літера, очищаємо буфер групи літер
"*"|"-"|"+") grup=' '; m=$(($m+1));;
?) grup=$grup$k; #якщо літера, добавляємо до буфера групи літер
ns[$m]=$grup; #зберігаємо в масив
esac
i=$(($i+1)) #переходимо до наступного символу строки
done
#3
for p in ${ns[*]}; #цикл по групах літер
do
j=0;
i=0;
ind='no';#індекатор
n=$((${#p} - 1));
#кількість символів групи
while [ $i -lt $n ];#цикл по символах групи
do
j=$(($i+1));
if [ ${p:$i:1} = 'a' ] && [ ${p:$j:1} = 'a' ] && [ $ind = 'no' ]
#перевірка чи є в групі "аа"
then
GrupAA=$GrupAA" "$p #якщо так, добавляємо до вихідних даних
ind='yes'
#"аа" присутні
fi
i=$(($i+1));
#переходио до наст. групи
done
ind='no' #в наст. груні ще невідомо чи є "аа"
done
#4 Виведення вхідного та зміненого тексту та набору спец. символів. Кінець алгоритму.
gdialog --title "Вихідні дані" --msgbox "Вхідний текст:$text\nВихідні дані:$GrupAA"
fi
gdialog --clear
#Кінець програми.
exit 0
Операційна система Windows. Системне програмування в MASM.
Регістри
Крім комірок оперативної пам'яті для короткочасного збереження даних використовуються регістри - комірки, що входять до складу процесора. Доступ до регістрів здійснюється значно швидше, ніж до комірок пам'яті, тому використання регістрів помітно зменшує час виконання програм. Крім того, у деяких випадках без регістрів узагалі неможливо обійтися.
Усі регістри мають розмір слова (16 бітів), за кожним з них закріплена визначена назва. За призначеням та способом використання регістри можна розбити на наступні групи:
- регістри загального призначення (AX, BX, CX, DX, BP, SI, DI, SP);
- сегментні регістри (CS, DS, SS, ES);
- лічильник команд (IP);
- регістр флагів (Flags).
Тлумачення цих назв:
- A accumulator, акумулятор;
- B base, база;
- C counter, лічильник;
- D data, дані;
- BP base pointer, покажчик бази;
- SI source index, індекс джерела;
- DI destination index, індекс приймача;
- SP stack pointer, покажчик стеку;
- CS code segment, сегмент команд;
- DS data segment, сегмент даних;
- SS stack segment, сегмент стеку;
- ES extra segment, додатковий сегмент;
- IP instruction pointer, лічильник команд.
Регістри загального призначення можна використовувати у всіх арифметичних і логічних командах. У той же час кожен з них має визначену спеціалізацію, тобто для деяких команд необхідні тільки визначені регістри. Наприклад, команди множення і ділення вимагають, щоб один з операндів знаходився в регістрі AX чи в регістрах AX і DX (у залежності від розміру операнду), а команди керування циклом використовують регістр CX як лічильник циклу. Регістри BX і BP зазвичай використовуються як базові регістри, а SI і DI - як індексні. Регістр SP як правило вказує на вершину стеку, апаратно підтримуваного ПК.
Регістри AX, BX, CX і DX конструктивно влаштовані так, що можна отримувати доступ до їх старшої і молодшої половин; можна сказати, що кожний з цих регістрів складається з двох регістрів, розмір яких один байт і що позначаються через AH, AL, BH, BL, CH, CL, DH, DL відповідно (H - high, старша; L - low, молодша). Таким чином, з кожним з цих регістрів можна працювати як з єдиним цілим, так і з його частинами. Наприклад, можна записати слово в AX, а потім зчитати тільки частину слова з регістра AH чи замінити тільки частину в регістрі AL і т.д. Така структура регістрів дозволяє використовувати їх для роботи і з числами так і із символами.
Всі інші регістри не діляться на частині, тому зчитувати чи записувати їхній зміст (16 бітів) можна тільки повністю.
Сегментні регістри CS, DS, SS і ES не можуть бути операндами ніяких команд, окрім стекових команд і команд пересилання. Ці регістри використовуються тільки для сегментування адрес.
Лічильник команд IP завжди містить адресу (зсув від початку програми) тієї команди, що повинна бути виконана наступною (початок програми зберігається в регістрі CS). Зміст регістра IP можна змінити тільки командами переходу.
Флаги
Процесор має спеціальний регістр флагів. Флаг - це біт, що приймає значення "1", якщо деяку умову було виконано, і значення "0" у іншому випадку. Використовуються 9 флагів, кожному з них привласнена визначена назва. Усі вони зібрані в регістрі флагів, тобто кожен флаг - це один з розрядів регістра. Структура регістра флагів:
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
x |
x |
x |
x |
OF |
DF |
IF |
TF |
SF |
ZF |
х |
AF |
x |
PF |
x |
CF |
Умовно флаги розділяються на флаги умов і флаги станів. Флаги умов автоматично змінюються при виконанні команд і фіксують ті чи інші властивості їх результату, наприклад, було чи ні переповнення або результат рівний нулю. Флаги станів встановлюються програмою і визначають подальшу роботу процесора, наприклад, блокують переривання.
До флагів умов відносять:
- CF (carry flag) - флаг переносу. Приймає значення 1, якщо операція призвела до перенесення зі старшого біта результату. Старшим є 7-й, 15-й, 31-й біти в залежності від розмірності операнда. Це відбувається, наприклад, якщо при додаванні цілих чисел результат вийшов за межі розрядної сітки, чи якщо при відніманні чисел без знаку перше з них було менше за друге. У командах зрушення в CF заноситься біт, що вийшов за розрядну сітку;
- OF (overflow flag) - флаг переповнення. Встановлюється в 1, якщо в результаті операції було виконано перенос у старший, знаковий біт (7-й, 15-й, чи 31-й). Встановлюється в 1, якщо відбувається позика з цих розрядів. Ця ознака необхідна для роботи з числами зі знаком;
- ZF (zero flag) - флаг нуля. Дорівнює 1, якщо результат операції виявився рівним 0;
- SF (sign flag) - флаг знаку. Встановлюється в 1, якщо в операції над знаковими числами було отримано від’ємний результат;
- PF (parity flag) – флаг парності. Дорівнює 1, якщо результат чергової команди містить парну кількість двійкових одиниць. Враховується звичайно при операціях вводу-виводу;
- AF (auxiliary carry flag) - флаг додаткового переносу. Фіксує особливості виконання операцій над двійково-десятковими числами.
До флагів станів відносять:
- DF (direction flag) - флаг напрямку. Встановлює напрямок перегляду рядків у строкових командах: при DF=0 рядки проглядаються від початку до кінця, при DF=1 - у зворотному напрямку;
- IF (interrupt flag) - флаг переривань. При IF=0 процесор перестає реагувати на переривання, що надходять до нього, при IF=1 блокування переривань знімається;
- TF (trap flag) - флаг трасування. При TF=1 після виконання кожної команди процесор робить переривання (з номером 1), що використовується при налагодженні програми для її трасування (виконання по кроках).
Завдання №2:
4. Даны натуральное число n, целые числа a1, …, an (в последовательности могут быть повторяющиеся члены). Получить все числа, которые входят в последовательность по одному разу.
EXE модуль програми:
assume CS:code, DS:Data
code segment
begin: mov ax,data
mov ds,ax
dec len ;будем делить на 2
mov bx,0 ;обнуляем регистры
mov ax,0
mov si,-1
ii: inc si
cmp si,len
ja fin
mov al,mas1[SI]
mov di,-1
jj: inc di
cmp di,len
ja k
cmp si,di
je jj
mov ah,mas1[di]
cmp ah,al
je ii
jmp jj
k: mov mas2[bx],al
inc bx
jmp ii
fin: mov si,bx
dec si
mov di,-1
vyv: inc di
mov bl,10
xor ax,ax
mov al,mas2[di]
div bl
add al,48
add ah,48
mov bl,ah
mov y,al
mov ah,09h
mov dx,offset y
int 21h
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
mov bl,0
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
cmp si,di
jne vyv
exit:
mov ah,4ch
int 21h
code ends
data segment
len dw 10
mas1 db 2,44,11,5,15,3,12,11,44,90
mas2 db 20 dup (0)
y db " $"
data ends
stk segment stack
db 256 dup()
stk ends
end begin
COM модуль програми:
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG,
ORG 100H ;Начало в конце PSP
begin: jmp l1
len dw 10
mas1 db 2,44,11,5,15,3,12,11,44,90
mas2 db 20 dup (0)
y db " $"
l1: dec len ;будем делить на 2
mov bx,0 ;обнуляем регистры
mov ax,0
mov si,-1
ii: inc si
cmp si,len
ja fin
mov al,mas1[SI]
mov di,-1
jj: inc di
cmp di,len
ja k
cmp si,di
je jj
mov ah,mas1[di]
cmp ah,al
je ii
jmp jj
k: mov mas2[bx],al
inc bx
jmp ii
fin: mov si,bx
dec si
mov di,-1
vyv: inc di
mov bl,10
xor ax,ax
mov al,mas2[di]
div bl
add al,48
add ah,48
mov bl,ah
mov y,al
mov ah,09h
mov dx,offset y
int 21h
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
mov bl,0
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
cmp si,di
jne vyv
exit:
mov ah,4ch
int 21h
codesg ends
end begin
Операційна система Windows. Системне програмування в MASM32 з використанням функцій API.
Завдання №3:
23. В матрице С(n,n) удалить в каждом столбце минимальный элемент столбца.
Код програми:
assume CS:code, DS:Data
code segment
begin: mov ax,data
mov ds,ax
mov bx,row
mov ax,col
mul bx
sub ax,col
mov dob,ax
mov bl,mas1
mov min,bl
mov cx,col
incCol: ;цикл по колонкам
push cx
mov di,cx
dec di
mov cx,row
mov min,254
incRow: ;цикл по рядкам
mov si,cx
dec si
mov bx,col
mov ax,si
mul bx
mov bx,ax
mov al,mas1[bx][di] ;в al заносим элемент масива
cmp min,al ;сравниваем текущий элемент с минимальным
jb less ;если минимальный меньше, то переход к след ел
mov min,al ;иначе присваиваем в мин текущий ел.
mov ind,si ; и сохраняем индекс мин элемента
less: loop incRow
mov si,ind
dec si
ii: inc si ;цикл по том же столбцу,
cmp si,row ; где мы начиная с сохраненного индекса сдвигаем элементы по столбику
je jj
mov bx,col
mov ax,si
mul bx
mov bx,ax
add bx,col
mov al,mas1[bx][di]
sub bx,col
mov mas1[bx][di],al
jmp ii
jj: pop cx
loop incCol
mov si,0
mov DI,0
dec col
fin: mov bl,10
xor ax,ax
mov al,mas1[DI]
div bl ;делим число на 10
add al,48 ;добавляем к младшей части 48, чтобы на вывод шел символ числа
add ah,48 ;добавляем к старшей части 48
mov bl,ah
mov y,al ;выводим младшую часть
mov ah,09h
mov dx,offset y
int 21h
mov y,bl ;выводим старшую часть
mov ah,09h
mov dx,offset y
int 21h
mov bl,0 ;после каждого элемента выводим пробел
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
cmp si,col
jne s
mov bl,10 ;после каждых col элементов выводим перевод строки
mov y,bl
mov ah,09h
mov dx,offset y
int 21h
mov si,-1
s: inc si
inc DI
cmp DI,dob
jne fin
mov ax,4c00h
int 21h
code ends
data segment
row dw 4
col dw 5
dob dw 1
min db 0
ind dw 0
mas1 db 61,31,13,99,1
db 11,22,6, 11,9
db 8, 12,5, 9,5
db 12, 3,12, 1,6
y db " $"
msg db ?
data ends
stk segment stack
db 256 dup()
stk ends
end begin