Some more Arithmetic Operations
2024.09.28 - [학교 수업/시스템 프로그래밍] - [시스템 프로그래밍] Race Condition
에서 봤었던 Assembly operations 이외의 명령어들은 다음과 같습니다.
Address Computation Instruction
leaq Src, Dest
- Load Effective Address (LEA)
- Src is address mode expression
- Set Dest to address denoted by expression (Dest is a register)
Uses
- Computing addresses without a memory reference(e.g., translation of p = &x[i];)
- Computing arithmetic expressions of the form x + k*y(* k = 1,2,4 or 8)
예를 들어 다음과 같은 코드가 있다면, 이에 해당하는 Assembly code는 다음과 같습니다.
/* C code */
long m12(long x)
{
return x*12;
}
/* Assembly code */
m12:
leaq (%rdi, %rdi, 2), %rax /* t <- x + x*2 */
salq $2, %rax /* return t<<2 */
Arithmetic Expression Example
/* C Code */
long arith(long x, long y, long z)
{
long t1 = x + y;
long t2 = z + t1;
long t3 = x + 4;
long t4 = y * 48;
long t5 = t3 + t4;
long rval = t2 * t5;
return rval;
}
/* Assembly Code */
arith:
leaq (%rdi,%rsi), %rax
addq %rdx, &rax
leaq (%rsi,%rsi,2), %rdx
salq $4, %rdx
leaq 4(%rdi,%rdx), %rcx
imulq %rcx, %rax
ret
* interesting things:
- C code의 순서와 Assembly code의 명령어 순서가 일치하지 않습니다. 이는 C code를 Assembly code로 바꾸는 최적화 과정에서 순서가 변경될 수 있기 때문입니다.
- imulq는 오직 한 번만 사용되었습니다. imulq는 leaq에 비해 연산의 속도가 매우 느리기 때문에 최적화 과정에서 왠만한 곱셈 연산은 lea연산으로 최적화됩니다.
- 사용되는 register의 개수가 6개입니다. 변수의 개수는 9개이지만, 변수의 개수만큼 register를 사용한다면 비효율이 너무 크기에, 최적화 과정에서 사용하는 레지스터를 겹치게 사용합니다.
Process State (x86-64, Partial)
Information about currently executing program
- Temporary data (e.g., %rax, ....)
- Location of runtime (%rsp)
- Location of current code control point (= PC) (e.g., %rip, ...)
- Status of recent tests (e.g., CF, ZF, SF, OF)
Condition Codes
Condition codes들은 가장 최근의 연산에 따라 ON/OFF가 되는 one bit register값 입니다. (= Single bit register)
예를 들어, 가장 최근의 연산이 다음과 같다면 ..
addq Src, Dest => t = a+b
- CF: Carry Flag (for unsigned) → if carry out from most significant bit (unsigned overflow)
- SF: Sign Flag (for signed) → if t < 0
- ZF: Zero Flag → t == 0 (as signed)
- OF: Overflow Flag (for signed) → if tow's complement (signed) overflow (= (a>0 && b>0 && t<0) || (a<0 && b<0 && t>0))
이때 leq연산을 통해서는 condition code들이 변하지 않습니다.
이를 직접 setting해주는 방식이 있습니다.
cmpq Src2, Src1
cmpq b,a like computing a-b without setting destination
이 연산은 Dest가 없기 때문에 a-b를 한 결과를 어디에 저장하지는 않습니다. 단지 condition code를 바꾸기 위함입니다. 이때 주의해야하는 점은 Src들의 순서입니다. Src2 - Src1 이 아니라 Src1 - Scr2 입니다.
- CF set: if carry out from most significant n=bit (used for unsigned comparisons)
- ZF set: if a==b
- SF set: if (a-b) < 0 (as signed)
- OF set: if two's-complement (signed) overflow
Reading Condition Codes
SetX Instructions
- Set low-order byte of destination to 0 or 1 based on combinations of condition codes → 최하위 byte에 대해서만 0 또는 1로 변경합니다.
- Does not alter remaining 7 bytes → 나머지 7bytes에 대해서는 건들이지 않습니다.
일반적으로 movzbl을 통해 작업을 끝냅니다.
/* C Code */
int gt(long x, long y)
{
return x > y;
}
/* Assembly Code */
gt:
cmpq %rsi, %rdi # Compare x:y
setg %al # Set when >
movzbl %al, %eax # Zero rest of %rax
* movzbl은 "mov명령어를 수행하는데, Zero로 나머지 값들을 맞추고, b (1byte)에서 l (4byte)로 데이터를 바꿔서 해라"라는 의미입니다. 추가적으로 b는 1byte, w는 2byte, l은 4byte, q는 8byte입니다.
int가 4byte이기 때문에 %eax (4byte단위 주소명)에 return값을 저장해서 return해줍니다.
Jumping (=jX instructions)
Jump to different part of code depending on condition codes
Conditional Expression
C allows goto statement. Jump to position designated by label
* you can make that assembly code to write
gcc -Og -s -fno-if-conversion control.c
long absdiff(long x, long y)
{
long result;
if(x>y)
result = x - y;
else
return = y - x;
return result;
}
# same
long absdiff_j(long x, long y)
{
long result;
int ntest = x <= y;
if(ntest) goto Else;
result = x - y;
goto Done;
Else:
result = x - y;
Done:
return result;
}
# Assembly Code
absdiff_j:
cmpq %rsi, rdi # x:y
jle .L4
movq %rdi, %rax
subq %rsi, %rax
ret
.L4: # x <= y
movq %rsi, %rax
subq %rdi, %rax
ret
Another Conditional Expression
C code
val = Test ? Then_Expr : Else_Expr;
Goto Version
ntest = !Test;
if (ntest) goto Else;
val = Then_Expr;
goto Done;
Else:
val = Else_Expr;
Done:
...
Do-while Loop
# C Code
long pcount_do(unsigned long x)
{
long result = 0;
do {
result += x & 0x1;
x >>= 1;
} while(x);
return result;
}
# Goto Version
long pcount_goto(unsigned long x)
{
long result = 0;
loop:
result += x & 0x1;
x >>= 1;
if (x) goto loop;
return result;
}
# Assembly Code
pcount_goto:
movl $0, %eax # result = 0
.L2:
movq %rdi, %rdx
andl $1, %edx # t = x & 0x1
addq %rdx, %rax # result += t
shrq $1, %rdi # r >>= 1
jne .L2 # if (x) goto loop
rep; ret
* interesting thing: x가 unsigned이기 때문에 shift연산이 자동적으로 shrq로 최적화 되었음을 알 수 있습니다.
General "Do-While" Translation
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Inter-Process Communication (3) | 2024.10.11 |
---|---|
[시스템 프로그래밍] Real-Time Signal (5) | 2024.10.08 |
[시스템 프로그래밍] Signal Examples (1) | 2024.10.06 |
[시스템 프로그래밍] Race Condition (0) | 2024.09.28 |
[시스템 프로그래밍] Signal Programming (0) | 2024.09.24 |