수를 입력받아서 1부터 그 수까지 더해서 출력하는 프로그램인데요
지금 저대로 nasm -f 실행하면 invalid combination of opcode and operands 뜨면서 안 되네요
저 코드에서 주석처리된 코드를 전부 살리고 for loop 루프 안에 있는 주석 코드 바로 위의 코드들을 주석처리하면 원하던 결과대로 잘 돌아가요
결론은 뭐가 문제인지 잘 모르겠습니다 저걸 어떻게 하면 될까요
그리고 dword 가 부호 없는 32 비트 정수를 나타낸다고 알고 있는데 [~~] 앞에 붙이는 것과 안 붙이는 것의 차이에 대해서 설명해주셨으면 좋겠습니다
지금 저대로 nasm -f 실행하면 invalid combination of opcode and operands 뜨면서 안 되네요
저 코드에서 주석처리된 코드를 전부 살리고 for loop 루프 안에 있는 주석 코드 바로 위의 코드들을 주석처리하면 원하던 결과대로 잘 돌아가요
결론은 뭐가 문제인지 잘 모르겠습니다 저걸 어떻게 하면 될까요
그리고 dword 가 부호 없는 32 비트 정수를 나타낸다고 알고 있는데 [~~] 앞에 붙이는 것과 안 붙이는 것의 차이에 대해서 설명해주셨으면 좋겠습니다
저번에 그 애지? 리하잉 ㅋㄷㅋㄷ
인텔 명령어는 기본적으로 두 operand(피연산자) 이상에 직접 메모리를 지정할 수 없다고 생각하면 돼.
즉, mov [eax], [ebx]나 cmp [eax], [ebx] 같은 건 전부 오류.
메모리는 최대 한 개만 지정해야 됨.
[] 를 C로 바꿔서 생각해보면 포인터 같은 느낌으로 생각하고 있었는데 잘못된 건가요
응 그 느낌으로 생각해도 돼. 당연히 그게 맞고.
근데 CPU의 명령어 처리 사이클 상 메모리에 접근하는 건 한번 뿐이라 피연산자에 메모리 접근을 두 개 이상 넣을 수 없어.
예를 들어 너가 *ptr2 = *ptr1; 로 C 코드를 짜도. 컴파일되면 reg = *ptr1; *ptr2 = reg; 식으로 컴파일 돼.
그러면 cmp [ebp-4], [ebp+8] 같은 경우에는 어떻게 바꿔야 할까요 ebp-4 가 가리키는 곳에 있는 값이랑 ebp+8 이 가리키는 곳에 있는 값을 비교하는 연산이라서 맞는 줄 알았는데..
주석 처리한 코드에서 EBX에 메모리 하나를 읽어놓고 EBX랑 메모리를 피연산자로 넘기는 식으로 레지스터에 미리 읽어놓고 레지스터 대 메모리 가 피연산자로 가게끔 짜면 돼. 즉 주석 처리한 코드가 정답 코드야.
아 그리고 MOV EAX, [EBX] 같은 코드에서 이걸 좀 정식 문법으로 표현하면 MOV EAX, DWORD PTR DS:[EBX] 인데
[ ... ] 가 포인터라는 건 확실하기 때문에 PTR은 생략이 가능한 거고, MOV, CMP 같은 명령어들은 기본적으로 operand가 크기가 같은 값들끼리만 처리하기 때문에 EAX의 크기를 보고 DWORD라는 걸 어셈블러가 추론할 수 있으므로 DWORD도 생략 가능해. 그래서 MOV EAX, DS:[EBX]만 써도 똑같은 의미가 됨. DS:는 생략하면 어셈블러가 알아서 세그먼트 추론해서 박아줌. 스택 관련 레지스터가 오면 SS로, 그 외엔 DS로 ㅋㄷ 어셈블러가 알아서 추측해 주기 때문에 생략이 가능한 거야.
만약에 MOV EAX, WORD PTR [EBX] 식으로 하면 오류가 난다. 공간과 크기가 같은 값이 와야 하거든.
만약에 MOVZX 같은, 두 오퍼랜드 크기가 다를 수 있는 명령어에선 메모리의 크기를 정확하게 밝혀줘야 된다.
ebx 에 저장된 주소에 있는 값과 eax 의 크기가 달라서 오류가 난다는 뜻인가요
EAX의 크기는 32비트인데 "WORD PTR [EBX]"는 표현대로라면 EBX에 의해 가리켜진 16비트 메모리 공간에서 읽어낸 16비트 값이니깐. 서로 크기가 달라서 오류가 나는 거지. MOV는 동일한 크기의 값만 처리할 수 있거든.
그리고 문제로 돌아가서 calc_sum 이라는 서브프로그램에서 짤처럼 ebx를 쓰지 않고 ebp-8하고 ebp-4만 사용하려고 하면 어떻게 해야 될까요
다른 예를 들자면 MOV EAX, BX가 오류가 나는 이유와 같음.
그거만 사용할 방법은 없다니까 그러네.
MOV EAX, BX 예로 보니까 이해가 좀 빠르게 되는 것 같네요
왜 EBX를 쓰기가 싫은 건데?
아 아예 없나요 ㅋㅋㅋㅋㅋㅋㅋㅋ
ㅇㅇㅇ 없어.
혹시 EBX에 다른 값을 넣어둬서 그 값 보존하려고 그런 거면 다른 레지스터를 쓰면 되고. 쓸 레지스터가 더 이상 없으면 적절한 레지스터 스택에 PUSH 해서 백업한 뒤 사용한 뒤 나중에 POP 해서 복구시키면 되징.
그게 정석이야.
서브프로그램에서 2개의 지역 변수를 사용한다는 조건을 생각해보면 이 2개의 지역 변수로만 구성해야 하지 않을까 해서..
만약 그런 단서가 문제에 달린 게 맞다면 그건 레지스터를 아예 쓰지 말라는 얘기가 아니라 서브 프로그램을 호출하기 전과 후에 레지스터 값에 변화가 없기만 하면 된다는(반환값을 보관하는 EAX 빼고) 말이야.
그러면 마지막 질문 하나만 더 할게요 mov ebx, dword [ebp-4] 에서 dword를 안 써주면 nasm -f 가 실행이 안 되던데
즉, 함수 시작할 때 SUB ESP, 8 이후에 PUSH EBX 해 놓고 MOV ESP, EBP 전에 POP EBX 해서 EBX 값을 함수 시작 시의 값을 백업해 놓고 끝날 떄 복구하게끔 짜면 돼.
[ebp-4] 의 크기를 정확히 알 수 없어서 dword 를 붙여줘야 한다는 건가요
그래? MASM32랑 다르네. 뭐 그럼 써 줘. 그 부분은 어셈블러마다 조금씩 다를 수 있어. 어셈블러가 추론해 주는 거니깐.
ㅇㅇ MASM32는 EBX의 크기 보고 자동으로 DWORD라고 추론해 주던데. NASM은 안 해주나 보다.
크기 문제였구나... 문제점 다 해결하고 가네요 ㅋㅋㅋㅋ 저번에도 친절하게 답변해주시더니 이번에도.... 감사합니다
http://autogram.tk/이
중고차 어플리케이션 어떤가요?