Компьютерийн зохион байгуулалт, ассемблер CS201

Preview:

DESCRIPTION

Компьютерийн зохион байгуулалт, ассемблер CS201. С.Байгалтөгс. ШУТИС - КТМС 2009 / Хавар. Лекц – 1 2 Стек \ STACK. MIPS Регистрүүд. Стек \STACK. Стек \STACK. Энэ сэдвээр стек болон стекийн заагч регистр $sp -н тухай үзнэ . Бүлгийн сэдвүүд: Стек - PowerPoint PPT Presentation

Citation preview

[www.cdeq.mn/hw200]

С.Байгалтөгс. ШУТИС-КТМС2009/Хавар

Компьютерийн зохион байгуулалт, ассемблер

CS201

Лекц – 12 Стек \STACK

[www.cdeq.mn/hw200]

MIPS Регистрүүд.

[www.cdeq.mn/hw200]

Стек \STACK

[www.cdeq.mn/hw200]

Энэ сэдвээр стек болон стекийн заагч регистр $sp-н тухай үзнэ.

Бүлгийн сэдвүүд: Стек Стекийн заагч регистр $sp Стекийн Push ба Pop үйлдлүүд. MIPS стек. Стекийн хөрвүүлэлтийн хэрэглээ. Жишээ тэмдэгт мөрийн урвуу хэлбэр. Анхааруулга: Энэ бүлэг дэх жишээ програмууд нь , SPIM симуляторийн псевдокомандууд нь ON ,

delayed branches нь OFF, мөн delayed loading нь OFF юм.

Стек \STACK

[www.cdeq.mn/hw200]

Стек нь санах ойд өгөгдөл зохион байгуулах аргачлал юм. Стек дэх өгөгдлүүдийн харагдац нь өрсөн тавагнууд шиг харагддаг байна. Өгөгдлүүдийг стек бүтцэд нэмэх эсвэл хасах нь өрсөн таваг нэмэх эсвэл эсвэл хасах аналог замаар явагддаг.

Энгийн үед стекийн бүх үйлдэл оройн хэсэгт (top) хийгдэнэ. Хэрэв таваг нэмэх хэрэгтэй бол тавгаа стекийн оройд байрлуулна.

Стек

[www.cdeq.mn/hw200]

Стек маягын үйл явцыг заримдаа "LIFO" буюу Last In First Out гэж нэрлэдэг.

Манай хичээлийн стек дэх өгөгдлийн элементүүд 32-бит үг (word) урттай. Ерөнхийдөө стекийг өгөгдлийн бүх төрөлд ашиглах боломжтой. Харин энэ сэдэвт стек нь зөвхөн 32-бит MIPS үг (word) агуулах юм.

Зурган дээр MIPS-ийн үг агуулсан стекийг үзүүлэв. Стекийн заагч регистр (Stack point register) болох $sp нь стекийн оройн хэсгийг заана. Стек заагч нь регистр $29 юм. Мнемоник регистр нэр $sp нь өргөтгөсөн ассемблерт ашиглагдана.

Хэвийн тохиолдолд стек санах ойг зурахдаа урвуу хэлбэртэй зурдаг. Зурган дээр стекийн оройн хэсэг нь 81 болох юм. Стекийн доод хэсэг нь -92 гэсэн бүхэл тоон утгыг агуулжээ.

Үйлдлийн систем эхлэхээс өмнө програм стект тохирсон санах ойн хязгаар бий эсэхийг баталгаажуулж тохирох хаягыг  $sp-д өгнө.

Урвуу(Upside-down) MIPS Стек

[www.cdeq.mn/hw200]

Урвуу (Upside-down) MIPS Стек

[www.cdeq.mn/hw200]

Програм хангамжийн хувьд $sp нь үргэлж стекийн оройн хэсгийг заана. Түүнчлэн стек нь доош буурах замаар өсдөг (Санах ойн хаягын зарчимаар). Иймд манай 4-байтын (full word) өгөгдөлтэй стекийн хувьд өгөгдөл нэмэхдээ $sp-ээс 4-ийг хасаж тухайн хаягт өгөгдлийг хадгална. Энэ үйлдлийг push гэж нэрлэнэ.

Өгөгдлийг стек рүү push хийхэд эхэлж стек заагчийн утгаас 4-ийг хасаж дараа нь стек заагчийн хаягт түүнийг хадгалдаг. Код дээр хэрхэн харагдахыг үзүүлэв. Стект оруулах утга нь регистр $t0-д хадгалагдаж байна:

# Өгөгдлийг PUSH the item in $t0: subu $sp,$sp,4 # шинэ өгөгдлийн байрлалыг

заана, sw $t0,($sp) # $t0-н агуулгыг тухайн шинэ

байрлал болгон хадгална

Push

[www.cdeq.mn/hw200]

Push

[www.cdeq.mn/hw200]

Стекээс өгөгдлийг гаргах үйлдлийг pop гэж нэрлэдэг. Програм хангамжийн хувьд стекээс өгөгдлийг “гаргах” үйлдэл гэдэг нь өгөгдлийг өөр байрлал руу хуулах ба стек заагч нь дахин тохируулагддаг гэж ойлгогдож болох юм.

Зурган дээр pop үйлдлийг үзүүлжээ. Эхлээд өгөгдөл стекийн оройн хэсгээс шинэ байрлал руу хуулагдаж дараа нь стекийн заагч нь 4-өөр нэмэгдэнэ.

Стекийн оройн элементийг pop хийхэд стек заагчийн зааж байгаа элементийг хуулсаны дараа стек заагчийн утга дээр 4-ийг нэмэх юм. Код дээр хэрхэн бичигдсэнийг үзүүлэв. Утгыг $t0 руу гаргая гэж санавал:

# $t0 руу элементийг гаргах:

lw $t0,($sp) # Элементийг $t0 руу хуулна.

addu $sp,$sp,4 # Хуучин оройн хэсгийн доор байрлах элементийг заана.

Pop

[www.cdeq.mn/hw200]

Pop

[www.cdeq.mn/hw200]

Регистрүүд ашиглагдаж байх үед стекийг ихэвчлэн өгөгдлийн утгыг түр зуур хадгалах зориулалтаар ашигладаг. Үүний жишээ нь стек ашиглан хөрвүүлэгч хэрхэн арифметик илэрхийллийг машин код руу хөрвүүлэхийг үзье. Арифметик илэрхийлэл нь ab - 12a + 18b – 7 ба зөвхөн регистр $t0 ба $t1-г ашиглах боломжтой.

SPIM нь програмыг ажиллуулж эхлэхээс өмнө стек заагч $sp-ийн утгыг зөв тодорхойлно. Бүхий л компьютер дээр стек заагчийн утгыг хэрэглэгчийн програм эхлэхээс өмнө үйлдлийн системээр тодорхойлогддог.

Жишээ програм:

Жишээ програм

[www.cdeq.mn/hw200]

# ab - 12a + 18b - 7 main: lw $t0,a # get a lw $t1,bb # get b mul $t0,$t0,$t1 # a*b subu $sp,$sp,_____ # push a*b onto stack sw $t0,______ . . . . . .data a: 2 bb: 3

Жишээ програм

[www.cdeq.mn/hw200]

Илэрхийллийн элементүүдийг стек рүү орууллаа (push). Дараа нь нийлбэрийн утга -7 гэж тавигдах ба элементүүдийг стекээс гаргаж (pop) нийлбэр дээр нэмнэ.

Програмын үргэлжлэл

[www.cdeq.mn/hw200]

# ab - 12a + 18b - 7 .globl main lw $t0,a # get a lw $t1,bb # get b mul $t0,$t0,$t1 # a*b subu $sp,$sp,4 # push a*b onto stack sw $t0,($sp) lw $t0,a # get a li $t1,-12 # mul $t0,$t0,$t1 # -12a subu $sp,$sp,4 # push -12a onto stack sw $t0,($sp) lw $t0,bb # get b li $t1,18 # mul $t0,$t0,$t1 # 18b subu $sp,$sp,4 # push 18b onto stack sw $t0,($sp) li $t1,-7 # init sum to -7 lw $t0,_____ # pop 18b addu $sp,$sp,______ addu $t1,$t1,$t0 # 18b -7 . . . .

Програмын үргэлжлэл

[www.cdeq.mn/hw200]

Хэрэв их хэмжээний регистрүүд боломжтой байсан бол илэрхийллийг стект биш регистрүүдэд хадгалаад явах боломжтой юм. Гэхдээ том хэмжээтэй програмд олон регистрүүд ашигласан ч яг энэ зарчмаар үйлдлүүд хийгдэнэ. Програмын бүтэн хувилбарыг үзүүлэв:

Бүрэн програм

[www.cdeq.mn/hw200]

# ab - 12a + 18b - 7 # Settings: Load delays OFF; Branch delays OFF, # Trap file ON; Pseudoinstructions ON .globl main main: lw $t0,a # get a lw $t1,bb # get b mul $t0,$t0,$t1 # a*b subu $sp,$sp,4 # push a*b onto stack sw $t0,($sp) lw $t0,a # get a li $t1,-12 # mul $t0,$t0,$t1 # -12a subu $sp,$sp,4 # push -12a onto stack sw $t0,($sp)

Бүрэн програм

[www.cdeq.mn/hw200]

lw $t0,bb # get b li $t1,18 # mul $t0,$t0,$t1 # 18b subu $sp,$sp,4 # push 18b onto stack sw $t0,($sp) li $t1,-7 # init sum to -7 lw $t0,($sp) # pop 18b addu $sp,$sp,4 addu $t1,$t1,$t0 # 18b -7 lw $t0,($sp) # pop -12a addu $sp,$sp,4 addu $t1,$t1,$t0 # -12a + 18b -7 lw $t0,($sp) # pop ab addu $sp,$sp,4 addu $t1,$t1,$t0 # ab - 12a + 18b -7 done: li $v0,1 # print sum move $a0,$t1 # syscall li $v0,10 # exit syscall .data a: .word 0 bb: .word 10

Бүрэн програм

[www.cdeq.mn/hw200]

Хамгийн сайн компьютерийн системд ч хязгаарлагдмал санах ойн орон зай байдаг. Иймээс програм анх ачаалагдахад үйлдлийн систем нь их хэмжээний стек зай өгдөг.

Зурган дээр үйлдлийн систем хэрхэн програмыг эхлэхэд санах ойг хэрхэн хуваарилж байгаа үзүүлжээ. 4Гбайтын боломжит санах ой байна. Санах ойн хэсэг нь 0x10000000-ээс 0x7FFFFFFF хүртэлх зайнд өгөгдлийн сегмент болон стек сегментэд зай гаргаж өгчээ. Энэ нь 1.8 Гигабайт зай.

Runtime Stack

[www.cdeq.mn/hw200]

Runtime Stack

[www.cdeq.mn/hw200]

Програм эхлэхдээ санах ойн заагчийн ($sp) утгыг 0x7FFFEFFC (хэрэглэгчийн санах ойн оройн хэсгийн доор байрлах үг (full word)-ийн хаяг) болгоно. Програм ажиллахад стек нь боломжит зай хүртэл доош чиглэж өснө. Харин өгөгдлийн сегмент нь дээш чиглэж өснө. Мэдээж динамик програмд сегментийг өсөж бас агшдаг. Хэрэв сегментүүдийн нэгдсэн зай нь боломжит зайнаас хэтэрвэл тэдгээрийн зааг нь хязгаарын дунд хэсгийн хаа нэгтэй тааралдана. Ингэвэл санах ой үлдээгүй гэсэн үг юм.

Санах ой зохицуулах арга нь 0x10000000 ээс 0x7FFFFFFF хоорондох зайн хагасыг стект, хагасыг нь өгөгдөлд хуваарилах явдал юм.

Runtime Stack

[www.cdeq.mn/hw200]

Заншил ёсоор бол машин командын сегментийг “text” нэрлэдэг. Сегмент ажиллаж эхлэх үед “process” гэж нэрлэгдэнэ.

Энд стекийн хэрэглээний сонгодог жишээг үзүүлэв. Хэрэглэгч тэмдэгт мөр оруулах ба програм үүнийг нь урвуу болгон гаралт руу бичнэ. Програмын хэрхэн ажиллаж байгааг ойлгохын тулд дараах диаграмыг үзүүлжээ. Тэмдэгт мөр "Hello“-г тэмдэгт тэмдэгтээр нь стек рүү push хийв. Дараа нь тэмдэгтүүд стекээс буцаж эх тэмдэгт мөр рүүгээ pop хийгдэнэ. Стек руу оруулсан сүүлийн тэмдэгт эхэнд стекээс гарна. Энэ үйлдэл нь тэмдэгтүүдийн байрыг сольж урвуу болгох юм.

Урвуу Тэмдэгт мөр

[www.cdeq.mn/hw200]

Стек дэх тэмдэгт бүр үгний (full word) доод эрэмбийн байтад хадгалагдах 2 байт хэмжээтэй юм.

Урвуу Тэмдэгт мөр

[www.cdeq.mn/hw200]

Програмын дүгнэлт. Тайлбарууд нь програмын гол хэсгийг илэрхийлнэ.

.text .globl main main: # input the string # push each character onto the stack # pop chars from stack back into the

buffer # print the reversed string .data str: .space 128 # character buffer

Дүгнэлт

[www.cdeq.mn/hw200]

Програмын эхний хэсэг нь терминалаас нэг мөр уншина.

Дараа нь, стекийн утгыг тохируулна. Null утгыг стек руу оруулна(push). Үүний дараа, энэ null хүртэлх утгуудыг гаргана (pop).

Эхний хэсэг

[www.cdeq.mn/hw200]

# Reverse and output a user-supplied string # Settings: Load delays OFF; Branch delays OFF, # Trap file ON; Pseudoinstructions ON # $t0 --- character pushed or popped # $t1 --- index into string buffer str .text .globl main main: # input the string li $v0,8 # service code la $a0,str # address of buffer li $a1,128 # buffer length syscall # initialize the stack: li $t0,_____ # push a null ____ $sp,$sp,4 # onto the stack sw $t0,(___) # to signal its bottom li $t1,0 # index of first char in str buffer

Эхний хэсэг

[www.cdeq.mn/hw200]

# push each character onto the stack # pop chars from stack back into the buffer # print the reversed string .data str: .space 128 # character buffer

Эхний хэсэг

[www.cdeq.mn/hw200]

Дараагийн алхам нь, тэмдэгтийн буфер дэх тэмдэгтүүдийг стек рүү нэг нэгээр нь оруулах юм. Эхний командыг тэмдэгтийг буферээс $t0-н байт руу ачаалахад ашиглана.

Дараа нь, ачаалсан тэмдэгтийг шалгана.Хэрэв энэ нь null (тэмдэгт) бол давталтаас гадуур салаалалтыг удирдана. Үгүй бол тэмдэгтийг стек руу оруулна (push). Гэх мэтээр энэ процесс давтагдана.

Тэмдэгтүүдийг оруулах (pushing)

[www.cdeq.mn/hw200]

# Reverse and output a user-supplied string # Settings: Load delays OFF; Branch delays OFF, # Trap file ON; Pseudoinstructions ON # $t0 --- character pushed or popped # $t1 --- index into string buffer str .text .globl main main: # input the string li $v0,8 # service code la $a0,str # address of buffer li $a1,128 # buffer length syscall li $t0,0 # push a null subu $sp,$sp,4 # onto the stack sw $t0,($sp) # to signal its bottom li $t1,0 # index of first char in str buffer

Тэмдэгтүүдийг оруулах (pushing)

[www.cdeq.mn/hw200]

# push each character onto the stack pushl: lbu $t0,str($t1) # get current char into # a full

word ____ $t0,stend # null byte: end of string subu $sp,$sp,4 # push the full word ___ $t0,($sp) # holding the char addu $t1,1 # inc the index j _____ # loop stend: . . . . . # pop chars from stack back

into the buffer # print the reversed string .data str: .space 128 # character buffer

Тэмдэгтүүдийг оруулах (pushing)

[www.cdeq.mn/hw200]

Тэмдэгт мөр дэх Null байт тааралдвал эхний давталт төгсөж дараагийн давталт эхлэнэ. Энэ дараагийн давталт нь стекийн доод хэсэгт байрлах null тэмдэгт дайралдах хүртэл тэмдэгтүүдийг стекээс гаргах юм. Стекээс гарах тэмдэгт бүр буферт хадгалагдах хуучин тэмдэгтүүдийг дарж хуулагдана.

Тэмдэгт мөрийн төгсгөлд байрлах null тэмдэгт дарж хуулагдахгүй.

Тэмдэгтүүдийг гаргах (popping)

[www.cdeq.mn/hw200]

. . . . . # push each character onto the stack pushl: lbu $t0,str($t1) # get current char into # a full word beqz $t0,stend # null byte: end of string subu $sp,$sp,4 # push the full word sw $t0,($sp) # holding the char addu $t1,1 # inc the index j pushl # loop # pop chars from stack back into the buffer stend: li $t1,0 # index of first byte of str buffer popl: ____ $t0,($sp) # pop a char off the stack ____ $sp,$sp,4 beqz $t0,done # null means empty stack ____ $t0,str($t1) # store at string[$t1] addu $t1,1 # inc the index j popl # loop # print the reversed string . . . . . .data str: .space 128 # character buffer

Тэмдэгтүүдийг гаргах (popping)

[www.cdeq.mn/hw200]

Програмын сүүлчийн шатанд тэмдэгтэн үр дүнг дэлгэцэнд хэвлэнэ.

Сүүлчийн шат

[www.cdeq.mn/hw200]

. . . . . # pop chars from stack back into the buffer stend: li $t1,0 # index of first byte of str buffer popl: lw $t0,($sp) # pop a char off the stack addu $sp,$sp,4 beqz $t0,done # null means empty stack sb $t0,str($t1) # store at string[$t1] addu $t1,1 # inc the index j popl # loop # print the reversed string done: li $v0,4 # service code la $a1,str # address of string syscall li $v0,10 # exit syscall .data str: .space 128 # character buffer

Сүүлчийн шат

Recommended