CS344-321 Assembly Language Programming Period 32
PARAMETER PASSING ในภาษาระดับสูง เมื่อมีการเรียกใช้โปรแกรมย่อย พารามิเตอร์อาจจะส่งผ่านทาง เรจิสเตอร์ หรือกองซ้อน หรือผสมกัน การผ่านทางเรจิสเตอร์จะเร็วกว่า แต่มีข้อจำกัด เนื่องจากจำนวน เรจิสเตอร์มีน้อย ถ้ามีพารามิเตอร์จำนวนมากไม่สามารถผ่านทางเรจิสเตอร์ได้หมด ต่อไปจะกล่าวถึงเฉพาะการผ่านพารามิเตอร์ทางกองซ้อน เนื่องจากการผ่านพารามิเตอร์ทางเรจิสเตอร์ตรงไปตรงมา ไม่ต้องกล่าวถึงอีก (ดูตัวอย่างการเรียกใช้บริการของ BIOS หรือ DOS หรือ atoi หรือ itoa) ตามข้อตกลงของภาษาระดับสูง เมื่อมีการเรียกใช้โปรแกรมย่อย จะเกิดกรอบกองซ้อน (activation record หรือ stack frame) ดังนี้
กรณี near call parameter 1 stack parameter 2 … จัดการโดยผู้เรียก … จัดการโดยผู้เรียก bp + 6 parameter n -1 bp + 4 parameter n bp + 2 return address bp dynamic link bp - 2 local variable 1 bp - 4 local variable 2 จัดการโดยผู้ถูกเรียก … local variable n กรณี near call
กรณี far call parameter 1 stack parameter 2 … จัดการโดยผู้เรียก … จัดการโดยผู้เรียก bp + 8 parameter n -1 bp + 6 parameter n bp + 2 return address bp dynamic link bp - 2 local variable 1 bp - 4 local variable 2 จัดการโดยผู้ถูกเรียก … local variable n กรณี far call
ผู้เรียกจะดำเนินการต่อไปนี้ - ถ้ามีพารามิเตอร์ กดค่าหรือเลขที่ของพารามิเตอร์ (ขึ้นอยู่กับว่าเป็นการส่งพารามิเตอร์แบบไหน) ลงบนกองซ้อนในช่วงกระทำการตามลำดับ จากตัวแรกถึงตัวสุดท้าย ถ้าเป็นภาษาปาสคาล ตัวสุดท้ายจะอยู่บนสุด แต่ถ้าเป็นภาษาซี จะทำกลับกัน - เรียกใช้ชุดคำสั่งย่อยหรือฟังก์ชันที่ต้องการ ภาษาแอสเซมบลี 8086/8088 มีคำสั่ง call ซึ่งทำหน้าที่นี้โดยตรง คำสั่ง call จะกดเลขที่กลับ (return address : เลขที่ของคำสั่งถัดจากคำสั่ง call) ลงบนกองซ้อนในช่วงกระทำการ แล้วกระโดดไปทำงานที่ชุดคำสั่งย่อยหรือฟังก์ชันที่ต้องการ (สถาปัตยกรรมบางแบบไม่มีคำสั่ง call โดยตรง ในกรณีนี้ต้องกดเลขที่กลับมาทำงานต่อ ลงบนกองซ้อนในช่วงกระทำการ แล้วใช้คำสั่งกระโดด เพื่อไปทำงานที่ชุดคำสั่งย่อยหรือฟังก์ชันที่ต้องการเอง)
ตัวอย่าง ภาษา Pascal procedure subr(para1:integer, var para2:integer, …, paran:integer) เรียกใช้ด้วย subr(para1, para2, …, paran); ภาษาเอสเซมบลี mov ax,para1 ; call by value push ax lea ax,para2 ; call by reference … mov ax,paran ; call by value call subr
ตัวอย่าง ภาษา C ซึ่งมีวิธีการผ่านค่าโดย value เท่านั้น subr(int para1, int para2, …, int paran) เรียกใช้ด้วย subr(para1, para2, …, paran); ภาษาเอสเซมบลี mov ax,paran push ax ... mov ax,para2 mov ax,para1 call subr
ผู้ถูกเรียก จะมีการดำเนินการ ดังต่อไปนี้ - กดค่าโยงพลวัต (dynamic link) ลงบนกองซ้อนในช่วงกระทำการ - จองเนื้อที่ให้กับตัวแปรท้องถิ่นบนกองซ้อนในช่วงกระทำการ เขียนเป็นคำสั่งภาษาแอสเซมบลี 8086/8088 ได้ ดังนี้ subr proc near push bp ; dynamic link mov bp,sp sub sp,_total_local_sizes เมื่อ total_parm_sizes เป็นเลขจำนวนเต็ม มีค่าเท่ากับขนาดของพารามิเตอร์รวมกันทั้งหมด
เมื่อผู้ถูกเรียกทำงานเสร็จ จะต้องลบกรอบกองซ้อนทิ้ง วิธีการลบทำได้ง่าย ๆ โดยการใช้คำสั่ง ต่อไปนี้ mov sp,bp pop bp ret total_parm_sizes subr endp เมื่อ total_parm_sizes เป็นเลขจำนวนเต็ม มีค่าเท่ากับขนาดของพารามิเตอร์รวมกันทั้งหมด
ตัวอย่าง จากโปรแกรมภาษาปาสกาล ข่อไปนี้ program final(input,output); var i,j:integer; procedure swap(var x,y:integer); var t : integer; begin t:=x; x:=y; y:=t; end; swap(i,j); end. จงเขียนโปรแกรมภาษาแอสเซมบลี 8086/8088 ให้ทำงานเหมือนโปรแกรมภาษา Pascal ข้างต้น โดยให้มีการผ่านพารามิเตอร์ทางกองซ้อน ตามข้อตกลงของภาษา Pascal
dosseg .model small .stack 128 .data ; define global variables here i dw ? j dw ?
.code swap proc near x equ [bp+6] ; parameter x y equ [bp+4] ; parameter y t equ [bp-2] ; local variable t push bp ; save old bp as dynamic link mov bp,sp ; set bp point to stack frame sub sp,2 ; allocate space for t push bx ; save content of bx mov bx,x ; t := x be careful x keeps address of i not value of i mov ax,[bx] ; keep value of x in ax mov t,ax ; then copy to t mov bx,y ; x:=y be careful x and y keep address of i and j mov ax,[bx] ; keep value of y in ax mov bx,x mov [bx],ax ; then copy to x mov ax,t ; y:=t , keep value of t in ax mov bx,y ; next instruction will copy to y mov [bx],ax ; after this i and j should be exchanged value
pop bx ; restore content of bx mov sp,bp pop bp ret 4 swap endp main proc near mov ax,@data mov ds,ax lea ax,i ; pass parameters (Pascal Convention) push ax lea ax,j call swap ; call swap mov ax,4c00h int 21h main endp end main
กรณี nested call หรือ recursive call เช่น main call A แล้ว A call B proc A { …; call B; … } proc B { … } จะเกิด stack frame บน stack ดังนี้ หมายเหตุ แสดงเฉพาะ dynamic link และ stack frame pointer
bp ของ main เป็นอะไร ก็ได้ bp stack frame ของ A bp stack frame ของ B