: 컴포넌트들 간에 바이트 정보들을 전송하는 시스템 내를 관통하는 전기적 배선군
int (*fp)(int x, int *p);
함수를 가리키는 포인터.
함수 포인터를 통해 메모리를 할당하거나 회수하는 것이 불가능하기 때문에 함수 포인터를 대상으로 malloc()과 free()를 사용하지 못한다.
int func(int x, int *p)
{
return x + *p;
}
int main(void) {
int n = 10;
int (*fp)(int x, int *p) = myfunc; // fp에 실제 함수 주소가 들어 있어야 함
fp(3, &n); // 또는 (*fp)(3, &n);
}
%rdi, %rsi, %rdx, %rcx, %r8, %r9` 최대 6개의 정수형 인자가 레지스터로 전달될 수 있다.
6개보다 많은 integral argument는 스택으로 내려가게 된다.
정수형(integral)/포인터형 인자에 한해서"라는 조건을 명시.
부동소수점 인자는 별도로 %xmm0~%xmm7을 씀
원조인 8086에서 레지스터들은 %ax~%sp까지의 16비트 레지스터를 가졌음
IA32로 확장하면서 이 레시스터들이 32비트로 확장되어 %eax~%esp까지 이름을 붙임
x86-64로 확장하면서 본래의 8개의 레지스터들이 %rax~%rsp까지 64비트로 확장되었고, 8개의 새로운 레지스터들이 추가됨
인스트럭션 집합의 역사적인 진화 과정으로 인해 여러 명명법을 따르게 되었고,
인스트럭션들과 각 하위 바이트들에 대한 호환성을 위해서.
x86 아키텍처가 16비트에서 32비트, 64비트로 발전하면서 기존 프로그램 및 명령어와의 하위 호환성을 유지하기 위해 기존 레지스터를 확장하는 방식으로 설계되었다. 따라서
%rax, %eax, %ax, %al은 하나의 레지스터에서 각각 64비트, 32비트, 16비트, 8비트 부분을 나타내는 구조를 갖게 되었다.
cmpl $0, %edi
jle .L1
movl $1, %edx
jmp .L2
.L1:
movl $0, %edx
.L2:
movl %edx, %eax
ret
int function(int x) {
int y;
if ( ____(1) )
_____(2);
else
y = 0;
return ____(3);
}
cmpl $0, %edi ; edi - 0 계산 (x와 0 비교)
jle .L1 ; x <= 0 이면 L1로 점프
movl $1, %edx ; (점프 안 했으면, 즉 x > 0 이면) → y = 1
jmp .L2
.L1:
movl $0, %edx ; (x <= 0) → y = 0
.L2:
movl %edx, %eax ; %edx의 값을 %eax로 옮기고 반환. 즉 return y;
ret
jle는 less than or equal
"x <= 0이면 .L1 else(y=0)로 간다"는 뜻
cmpl $0, %edi
jle .L1
→ x <= 0이면 .L1로 감
→ .L1이 y=0이므로
→ 반대로 x > 0이면 y=1
⇒ 인자 x를 조건 검사에만 쓰고, 실제로 값을 대입·반환하는 변수는 전부 y
int function(int x) {
int y;
if (x > 0)
y = 1;
else
y = 0;
return y;
}