물론 UB 임. 하지만 많은 컴파일러들이 아래처럼 동작됨.
int some_function()
{
return value;
}
형식의 함수가 있다면,
대략 아래와 같은 어셈블리 코드로 번역됨
MOV EAX, value
RET
리턴값이 8비트 리턴일땐 AL, 16비트 일땐 AX, 32비트 일땐 EAX, 64비트 일땐 EDX:EAX
조합을 사용함. ( 64비트 컴파일러 에선 물론 이름이 바뀜 r~~ )
즉, 리턴값을 가져다 쓰는쪽이 EAX 를 쓰게 컴파일되는 식임.
따라서,
void some_function()
{
asm mov EAX, value;
}
를 한다면, 사실상 똑같음.
우연히 대입되었던 EAX 를 조사하는 용도로도 쓸 수 있음.
앞에 질문한 아이의 소스코드가
왜 다른 레지스터도 아니고 EAX를 사용해 계산되었는가는,
EAX, EBX, ECX, EDX 가 A,B,C,D 레지스터라고 해서 Intel CISC 계열의 범용레지스터( GPR ) 로 활용되긴 하지만,
B, C, D 는 각각 옵셋계산, 카운터, 데이타 용도로 약한 특수 목적을 갖고 있다( SPR )는 이유임.
EAX 를 다른말로 어큐뮬레이터 라고 부르는건 EAX 를 경유하는 계산들이 많기 때문.
아까 그 함수에서 왜 a가 eax에 잡혔는지를 잘 모르겠읍니다
글에 부연했음.
한가지 덧붙여서 호출규약 을 볼 필요가 있음.
제가 헷갈렸던 부분은 호출하면 파라미터를 edi(a) esi(b)로 전달했을텐데 edi -> eax, add esi가 된것 같아서요
걍 edi에서 더할 수도 있지 않나 해서
각각의 calling convention 들이 스택과 레지스터를 경유하는 인자 전달을 약속하는데, 컴파일러 최적화가 걸릴 경우 eax 를 통한 리턴을 고려해 eax 를 비우는 경향이 있음. 그래서 eax 쪽으로 연산의 결과를 몰아가는 것.
보통 edi, esi 로 파라메터를 넘기진 않습니다.
source index 는 스트림 연산의 원본, destination index 는 스트림 연산의 대상 을 가리키는 용도로 주로 사용됩니다.
두 레지스터들은 고전적으로 값을 직접 연산에 사용하지 못해서 eax 를 경유하게 설계되어 있구요.
아 호출방식은 저거 x64보고 공부했던건데 86은 다른가봄
연산을 못하니까 eax로 가면 말이 되네요
이게 대상 운영체제 타입에 따라서도 다르긴 합니다.
원래 물리적 메모리에 접근하도록 설계된 세그먼트 / 인덱스 레지스터들이 운영체제에 따라 가상메모리 구조체의 인덱스 정도로 변경되기도 하거든요.
암튼 컴파일러 구현하기 나름이쥬.
저걸 걍 항상 레지스터를 이용해서 넘기는줄 알았는데 보니까 아니네요 스택도 쓰고 그러네
원래 스택을 경유한 전달이 가장 기본입니당~
컴파일러가 extreme한 최적화를 걸든, 아니면 fastcall 같은걸 쓸 때 레지스터를 사용하죠. ( 물론 스택이라는 개념이 없는 환경도 있습니다 )
오... 신기하네여. 컴구 안들었으면 하나도 이해 못할뻔했넴
rdi rsi는 x64에서만 그런거였네요 x86은 머 다양하게 있네