You are on page 1of 9

Thi giữa kỳ: Chương trình hệ thống

Thời gian: 60 phút (Được sử dụng tài liệu)

Bài 1. Cho hàm f trên ngôn ngữ lập trình C như sau:
int f(int a, int b, int n) {
if (n == 0) return a;
else return f(a + b, b, n - 1);
}

1. Hãy viết các đoạn mã hợp ngữ tương ứng với lời gọi f(1,2,3) trong các trường hợp giả định sau:
a. Hàm f sử dụng quy ước gọi hàm cdecl
b. Hàm f sử dụng quy ước gọi hàm pascal
c. Hàm f sử dụng quy ước gọi hàm fastcall
2. Hãy viết đoạn mã hợp ngữ của hàm f trong các trường hợp giả định.
a. Hàm f sử dụng quy ước gọi hàm cdecl
b. Hàm f sử dụng quy ước gọi hàm fastcall
Bài 2.
Một chương trình C được dịch sang hợp ngữ như sau.

1. Hãy cho biết kết quả thực hiện của chương trình?
2. Mô tả trạng thái của ngăn xếp tại các dòng (46)
3. Hãy hình dung chương trình nguồn C có thể biên dịch thành đoạn mã nêu trên.
Bài 3.
Một trình liên kết thực hiện liên kết các tệp đối tượng đầu vào X, Y, và Z. Kích thước các đoạn của
từng tệp đối tượng X, Y và Z được mô tả trong bảng sau:
X Y Z
Text 0x2047 0x1243 0x857
Data 0x3123 0x2016 0x209
BSS 0x6501 0x3994 0x463
1. Hãy thực hiện hoạch định bộ nhớ cho tệp thực thi bằng cách điền địa chỉ cơ sở cho từng đoạn
của từng module (tệp đối tượng) vào bảng sau:
X Y Z
Text
Data
BSS
Lưu ý:
- Mã đối tượng bắt đầu từ trang nhớ 1 (0x1000)
- Kích thước mỗi trang nhớ là 0x1000
2. Trong module X, Y và Z, tồn tại một số liên kết được mô tả như sau:

Trong đó:
- Tham chiếu (A) là tham chiếu tuyệt đối có giá trị 0x2684 (tính theo địa chỉ cơ sở của đoạn
data)
- Tham chiếu (B) là tham chiếu ngoài module, tới điểm tham chiếu trên Y có giá trị 0x388
(tính theo địa chỉ cơ sở của đoạn text)
- Tham chiếu (C) là tham chiếu tuyệt đối có giá trị 0x3048 (tính theo địa chỉ cơ sở của đoạn
BSS)
- Tham chiếu (D) là tham chiếu ngoài module, tới điểm tham chiếu trên Z có giá trị 0x280
(tính theo địa chỉ cơ sở của đoạn text)
- Tham chiếu (E) là tham chiếu tương đối, có giá trị 0x250
Xác định giá trị địa chỉ tham chiếu của (A), (B), (C), (D) và (E) sau khi tái định vị.
GK:
Bài 1
1. Gọi hàm function(1, 2, 3)
Với chương trình chạy như sau:
int main(){

function(1, 2, 3);

}
a. Cách gọi cdecl
pushl $3
pushl $2
pushl $1
call function
addl $12, %esp
b. Cách gọi pascal
pushl $1
pushl $2
pushl $3
call function
c. Cách gọi fastcall
movl $1, %eax #a
movl $2, %edx #b
movl $3, %ecx #n
call function

2. Mã hợp ngữ của hàm


a. Cách gọi hàm cdecl

function:
pushl %ebp # Cho biến ebp vào stack chứa
# thông tin của trang
movl %esp, %ebp # Đồng bộ %esp và %ebp
# để %ebp giữ vị trí còn %esp di chuyển để lưu
# dữ liệu
# stack: n, b, a, return (addr), old ebp (esp ở
đây)
movl 16(%ebp), %edx #n
movl 12(%ebp), %ecx #b
movl 8(%ebp), %eax #a
cmpl $0, 16(%ebp) # so sánh n với 0
jne L1
jmp END # Thoát
L1:
subl $1, %edx # n mới = n cũ - 1
addl %ecx, %eax # a mới = a cũ + b
pushl %edx
pushl %ecx
pushl %eax
call function # function(a cũ + b, b, n cũ - 1)
addl $12, %esp # stack còn n, b, a => Giải phóng cả 3
jmp END
END:
leave
ret

b. Cách gọi hàm fastcall


function:
pushl %ebp # Cho biến ebp vào stack chứa
# thông tin của trang
movl %esp, %ebp # Đồng bộ %esp và %ebp
# để %ebp giữ vị trí còn %esp di chuyển để lưu
# dữ liệu
movl %eax, 12(%ebp) #a
movl %edx, 8(%ebp) #b
movl %ecx, 4(%ebp) #n
# stack: return (addr), a, b, n, old ebp (esp ở đây)
cmp $0, 4(%ebp) # So sánh n với 0
jne L1
jmp END
L1:
movl 12(%ebp), %esi # Truyền giá trị a sang %esi
movl 4(%ebp), %ebx # Truyền giá trị n sang %ebx
addl 8(%ebp), %esi # %esi = %esi + b (a = a+b)
subl $1, %ebx #n=n-1
movl %esi, %eax # Truyền lại %esi(a mới) vào %eax
movl 8(%ebp), %edx # Truyền lại 8(%ebp) (b) vào %edx
movl %ebx, %ecx # Truyền lại ebx vào (n) vào %ecx
call function
jmp END
END:
leave # Kết quả đã lưu sẵn trong %eax
ret # Nạp %esp vào bộ %ebp và thoát

Bài 2:
1. Kết quả thực hiện chương trình
Nên chương trình sẽ có kết quả in ra là 3
2. Trạng thái dòng (46)
Lưu kết quả từ -4(%ebp) ra %eax để return kết quả

3. Hình dung chương trình nguồn


(Tự viết code C)
#include <stdio.h>

int a[] = {1, 2, 1, 3, 1};

int count(int n, int x) {


if (n < 0) {
return 0;
}
if (a[n] != x) {
return count(n - 1, x);
}
return count(n - 1, x) + 1;
}

int main() {
printf(“%d\n”, count(4, 1));
return 0;
}
Đây là chương trình đếm số phần tử trong mảng int a[] = {1, 2, 1, 3, 1} xem có phần
tử nào bằng với tham số truyền cho count (mà ở đây là 1) nên có kết quả trả lại
cho %eax là 3

Bài 3:
1. Thực hiện hoạch định bộ nhớ

Mã đối tượng bắt đầu từ 0x1000


Kích thước mỗi trang nhớ là 0x1000

Kích thước ban đầu

X Y Z

Text 0x2047 0x1243 0x857

Data 0x3123 0x2016 0x209

BSS 0x6501 0x3991 0x463

Khi hoạch định bộ nhớ (Đọc từ trái sang phải, từ trên xuống dưới, địa chỉ làm tròn
lên để là số chia hết cho 4 cho chắc ăn):
Từ Text sang Data do khác tính chất nên phải dịch tròn lên thành 0x5000, còn Data
và BSS có cùng tính chất nên không cần (theo slide)

X Y Z

Text 0x1000 0x3048 0x428C

Data 0x5000 0x8124 0xA13C

BSS 0xA348 0x1084C 0x141E0

2. Xác định địa chỉ tham chiếu sau khi tái định vị

(A) là tham chiếu tuyệt đối có giá trị 0x2684 (tính theo địa chỉ cơ sở data). Chuyển
tham chiếu tới data.
(B) là tham chiếu ngoài module tới Y có giá trị 0x388 (tính theo địa chỉ cơ sở đoạn
text)
(C) là tham chiếu tuyệt đối có giá trị 0x3048 (tính theo cơ sở của đoạn BSS)
(D) là tham chiếu ngoài module tới điểm Z có giá trị 0x280 (tính theo cơ sở của đoạn
text)
(E) là tham chiếu tương đối có giá trị 0x250

Sắp xếp lại


A: 0x5000 + 0x2684 =
B: 0x3048 + 0x388 =
C: 0x1084C + 0x3048 =
D: 0x428C + 0x280 =
E: E + 0x250 = ?
CS107 x86-64 Reference Sheet
Common instructions push src add to top of stack
mov src, dst dst = src Mem[--%rsp] = src
movsbl src, dst byte to int, sign-extend pop dst remove top from stack
movzbl src, dst byte to int, zero-fill dst = Mem[%rsp++]
cmov src, reg reg = src when condition holds, call fn push %rip, jmp to fn
using same condition suffixes as jmp ret pop %rip

lea addr, dst dst = addr Condition codes/flags


ZF Zero flag
add src, dst dst += src SF Sign flag
sub src, dst dst -= src CF Carry flag
imul src, dst dst *= src OF Overflow flag
neg dst dst = -dst (arith inverse)

imulq S signed full multiply Addressing modes


R[%rdx]:R[%rax] <- S * R[%rax] Example source operands to mov
mulq S unsigned full multiply
same effect as imulq Immediate
mov $0x5, dst
idivq S signed divide $val
R[%rdx] <- R[%rdx]:R[%rax] mod S source is constant value
R[%rax] <- R[%rdx]:R[%rax] / S
divq S unsigned divide - same effect as idivq Register
cqto R[%rdx]:R[%rax] <- SignExtend(R[%rax]) mov %rax, dst
%R
sal count, dst dst <<= count R is reg ister
sar count, dst dst >>= count (arith shift) source in %R register
shr count, dst dst >>= count (logical shift)
and src, dst dst &= src Direct
or src, dst dst |= src mov 0x4033d0, dst
xor src, dst dst ^= src 0xaddr
not dst dst = ~dst (bitwise inverse) source read from Mem[0xaddr]

cmp a, b b-a, set flags Indirect


test a, b a&b, set flags mov (%rax), dst
(%R)
set dst sets byte at dst to 1 when condition R is register
holds, 0 otherwise, using same source read from Mem[%R]
condition suffixes as jmp
Indirect displacement
jmp label jump to label (unconditional) mov 8(%rax), dst
je label jump equal ZF=1 D(%R)
jne label jump not equal ZF=0 R is register
js label jump negative SF=1 D is displacement
jns label jump not negative SF=0 source read from Mem[%R + D]
jg label jump > (signed) ZF=0 and SF=OF
jge label jump >= (signed) SF=OF Indirect scaled-index
jl label jump < (signed) SF!=OF mov 8(%rsp, %rcx, 4), dst
D(%RB,%RI,S)
jle label jump <= (signed) ZF=1 or SF!=OF
ja label jump > (unsigned) CF=0 and ZF=0 RB is register for base
RI is register for index (0 if empty)
jae label jump >= (unsigned) CF=0
D is displacement (0 if empty)
jb label jump < (unsigned) CF=1
S is scale 1, 2, 4 or 8 (1 if empty)
jbe label jump <= (unsigned) CF=1 or ZF=1
source read from:
Mem[%RB + D + S*%RI]
CS107 x86-64 Reference Sheet
Registers Instruction suffixes
%rip Instruction pointer b byte
%rsp Stack pointer w word (2 bytes)
%rax Return value l long /doubleword (4 bytes)
%rdi 1st argument q quadword (8 bytes)
%rsi 2nd argument
Suffix is elided when can be inferred from
%rdx 3rd argument
operands. e.g. operand %rax implies q,
%rcx 4th argument
%eax implies l, and so on
%r8 5th argument
%r9 6th argument
%r10,%r11 Callee-owned
%rbx,%rbp,
%r12-%15 Caller-owned

Register Names
64-bit register 32-bit sub-register 16-bit sub-register 8-bit sub-register
%rax %eax %ax %al
%rbx %ebx %bx %bl
%rcx %ecx %cx %cl
%rdx %edx %dx %dl
%rsi %esi %si %sil
%rdi %edi %di %dil
%rbp %ebp %bp %bpl
%rsp %esp %sp %spl
%r8 %r8d %r8w %r8b
%r9 %r9d %r9w %r9b
%r10 %r10d %r10w %r10b
%r11 %r11d %r11w %r11b
%r12 %r12d %r12w %r12b
%r13 %r13d %r13w %r13b
%r14 %r14d %r14w %r14b
%r15 %r15d %r15w %r15b

You might also like