함수이름은 어떻게 정의 될까?
#include <stdio.h>
int asm_main();     // 어셈블리 파일로 만들예정
int main()
{
    int n = asm_main();
    printf("result : %d\n", n);
}
; asm1.asm
.model flat
public _asm_main
.code
_asm_main:
    mov     eax, 100        ; return 100과 동일
    ret
end     ; 파일의 끝에는 항상 end가 있어야 한다.
- cpp에서는 함수의 이름을 
asm_main()로 선언했는데 어셈블리에선_asm_main라 정의한 이유??
cl컴파일러는 함수의 이름 앞에_를 붙여서 쓴다. cl컴파일러의 규칙을 따르기 위해서 추가함. 
.model flat 이란
.model에서는 세 가지를 정의할 수 있다.- memory model
 - language-type
 - stack-option
 
memory model의 경우 32bit 응용프로그램의 경우 flat으로 정의 하고 16bit는 여러가지가 있는데 16는 쓰일일이 없으니 설명은 생략한다.language-type의 경우 c, stdcall로 정의가능한데 이후에 별도로 설명한다stack-option의 경우 32bit에서는 사용이 안되고 16bit에서는 여러 설정이 있지만 역시 설명은 생략
대략적 사용은 아래와 같이 한다.
.model flat             ;
.model flat, c          ; language-type을 c로
.model float, stdcall   ; language-type을 stdcall로
PE Format이란?
C++로 실행파일(exe)을 만들시 내부메모리 구조는 아래와 같다
Header
-------
Section .text (함수가 들어있다)
Section .data (전역 변수가 들어있다)
...
C++에서는 Section .text, .data를 알아서 컴파일러가 정리해줬다고하지만…
 어셈블리에서는 어떻게 정리할까?
.model flat
public _asm_main ; 다른 함수에서도 부르게 해달라는 명령(c에서 부를수 있게 된다.)
.data
; Section .data를 의미한다
; 전역 변수이다
.code   ; .text 를 의미한다.
_asm_main:
    mov     eax, 100    ; eax레지스터는 보통 반환값을 넣는 용도로 사용됨
    ret ; 함수 종료(return)를 의미
end
PE에 관해서는 이후 DLL설명에서 추가설명을 넣음.
 일단 PE Format이라는게 바이너리가 Header Section .text(함수), Section .data(변수)로 구분된다고 기억하자
또 다른 어셈블리 표기법
함수를 또 다른 방법으로 표기
.model flat
public _asm_main
.code
_asm_main proc  ; 콜론(:)대신 proc표기가능 
    mov     eax, 100
    ret
_asm_main endp  ; proc가 끝났다고 알린다
end
Section을 또 다른 방법으로 표기
.model flat
public _asm_main
_DATA SEGMENT   ; .data와 동일
_DATA ends
_TEXT SEGMENT    ; .code 대신에 _TEXT SEGMENT 표기가능
_asm_main proc
    mov     eax, 100
    ret
_asm_main endp
_TEXT ends
end
C소스를 어셈블리 파일로 생성하기
# asm1.c를 어셈블리 언어로 표현해주세요
$ cl asm1.c /FAs /c
/FAs: 어셈블리를 만들어 달라/c: 컴파일만 해달라
Data section
.model flat
public _asm_main
.data
L1  DWORD   100     ; 4바이트 할당 100을 넣어라
L2  DD      200     ; DD = DWORD와 동일어
L3  DD      ?       ; 초기값을 정의하고 싶지 않다면 ?를 넣자
.code
_asm_main:
    mov     eax, L1 ; 100이 리턴
    ; 메모리 복사
    ; mov     L1, L2  ; 컴파일 에러 : 2개의 오퍼랜드가 모두 메모리일 수 없다.
    mov     ebx, L2
    mov     L1, ebx
    ; 이런식으로 해야함
    ; 메모리 주소값 구하기
    ; ebx = &L1
    mov     ebx, offset L1  ; L1의 메모리주소를 넣어라
    mov     eax, [ebx]      ; []는 C의 *와 동일 *ebx(ebx가 가리키는 값 = L1값)
    ; ebx = 300
    ; mov     [ebx], 300            ; 에러 : 300을 몇 바이트(int, short)로 넣을지 미정
    mov     dword ptr[ebx], 300     ; dword(2바이트)로 넣어주세요
    ret
end
; 배열 만들어 보기
.model flat
public _asm_main
.data
; L1   DD   100
L1   DD   100, 200, 300, 400
L2   DD   4 dup (100) ; 100, 100, 100, 100
; 4개의 100을 넣어달라
.code
_asm_main:
    ; mov eax, L1
    mov esi, offset L1
    mov eax, dword ptr[esi+4]
    ret
end
여기서 궁금한 점 레지스터는 어디까지 있나??
eax, ebx … 어디까지 있는거지??
- 참고사이트 : 알파벳 순이 아니라 용도에 따라 사용되는 레지스터가 다르다
 
함수 호출의 원리
jump 함수호출
.model flat
public _asm_main
public _foo
.code
_asm_main:
    mov eax, 100
    ; 여기서 _foo를 호출하고 싶다면?
    ret
_foo:   ; 참고로 c에서도 호출하게 하고 싶어서 _를 앞에 붙임
end
- 함수를 호출하는 방법 
jmpcall
 
jmp
_asm_main:
    mov eax, 100
    mov ebx, POS_A      ; 함수를 호출 후 POS_A로 돌아오게 해주세요
    ; mov ebx, 돌아올 주소
    jmp _add ; 함수 호출
POS_A:
    ret
_add:
    mov eax, 300
    jmp ebx             ; ebx에 리턴 후 돌아갈 주소가 남겨져 있기에 jmp하면 돌아감
ebx에 돌아갈 주소를 넣어둘 경우 ebx는 함수가 종료될때까지 사용하지 못하게된다.
 ebx를 써야할 필요가 발생한다면??? 
 해결해보자
_asm_main:
    mov eax, 100
    ; mov ebx, 돌아올 주소
    push POS_A
    jmp _add ; 함수 호출
POS_A:
    ret
_add:
    mov eax, 300
    pop ebx ; ebx에 pop해달라
    jmp ebx
call 함수호출
_asm_main:
    mov eax, 100
    call _add   ; 스택에 넣고 돌아올 주소까지 할당
    ret
_add:
    mov eax, 300
    ret         ; 스택에 꼭대기에 돌아갈 주소가 있다고 가정
- 결론 : 
call, ret을 쓰자 
C를 어셈블리로 만들어서 call을 어떻게 사용하나 보자
int add()
{
    return 300;
}
int main()
{
    add();
}
이걸 어셈블리로 만들어 보자.
cl call.c /FAs
결론은 call, ret을 VS에서도 그대로 쓴다는 것을 확인하는 것이다.
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.28.29914.0 
include listing.inc
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
PUBLIC	add
PUBLIC	main
pdata	SEGMENT
$pdata$main DD	imagerel $LN3
	DD	imagerel $LN3+16
	DD	imagerel $unwind$main
pdata	ENDS
xdata	SEGMENT
$unwind$main DD	010401H
	DD	04204H
xdata	ENDS
; Function compile flags: /Odtp
; File C:\Git\Example\Example\call.c
_TEXT	SEGMENT
main	PROC
; 7    : {
$LN3:
	sub	rsp, 40					; 00000028H
; 8    :     add();
	call	add
; 9    : }
	xor	eax, eax
	add	rsp, 40					; 00000028H
	ret	0
main	ENDP
_TEXT	ENDS
; Function compile flags: /Odtp
; File C:\Git\Example\Example\call.c
_TEXT	SEGMENT
add	PROC
; 3    :     return 300;
	mov	eax, 300				; 0000012cH
; 4    : }
	ret	0
add	ENDP
_TEXT	ENDS
END