_start:
|
'어셈블리(assembly) > 어셈블리 실습' 카테고리의 다른 글
9월 4일 conditional jump (0) | 2013.09.04 |
---|---|
8월 28일 어셈블리 mul, imul,연습문제 (0) | 2013.08.29 |
3월 28일 inc, dec, neg (0) | 2013.08.29 |
8월 27일 실습2(정리중) (0) | 2013.08.27 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
_start:
|
9월 4일 conditional jump (0) | 2013.09.04 |
---|---|
8월 28일 어셈블리 mul, imul,연습문제 (0) | 2013.08.29 |
3월 28일 inc, dec, neg (0) | 2013.08.29 |
8월 27일 실습2(정리중) (0) | 2013.08.27 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
conditional jump는 상태적이 점프 ?
ㅋㅋㅋ
상황에 따라 점프를 할 수도 있고 안 할 수 도 있다는 얘기이다. 명령어는 jns, jnz....등이 있다.
이에 비해 unconditional jump는 무조건 특정한 곳으로 점프하는 명령어이다. 명령어 jmp가 된다.
아래 그림들과 같이 C언어 소스와 disassembly를 이용하여 비교하여 생각해보자.
아래 부분은 if문이다.
jns명령어를 주목한다. jns는 jump not set의 줄임말.
flag bit sf는 sign flags. 이 비트가 0이 아니라면, 이라는 뜻으로 해석한다.
즉, 1이 아니면, 음수가 아니라 양수라는 뜻이다. 그렇다면, if문의 조건인 0보다 작다는
성립하지 않는다. 따라서 jns가 실행이 되어 if문이 아래 코드가 실행되지 않고 else if문으로
점프한다.
만약에 음수라면 아래 코드가 실행이 되고 jmp명령어가 실행되어 else문 다음코드로 실행이 된다.
else if,else
자, else if문에 코드를 좀 변경해 보겠다.
위의 그림에는
cmp dword ptr[a], 0
jne main +43h 라고 코드가 되어있다. 이것은 컴파일러가 최적화 해서 나타낸 코드
지금 단계에서는 어려움이 있으므로 이 부분을 고치면, 다음과 같다.
jnz else의 주소(else의 주소를 알 수 없으므로...)
if문 끝에 jmp와 else if문 다음에 있는 jmp를 자세히 보면 숫자가 같다. 즉, 같은 곳으로 jump를 한다는 의미.
아마도 else문 다음에 나와있는 것은 컴파일러가 disassembly를 하면서, 화면상 이상하게 나온거.
실제 코드상의 위치는 각각, if문과 else if문 끝에 jmp명령어가 위치한다.
if~else if~else문까지 있는데 끝을 나타낸다. 그래서 if문이 실행된 경우 else if, else문이 실행되지 않는다.
아래는 교재에서 설명하는 부분.
자, 교재에는 elseIfZero: jnz elsepos라고 되어있다. 즉, else if문의 조건이 거짓이면, elsepos로 점프한다는
뜻이다.
빨간색 네모의 영문과 not ture.까지 해석을 한다면, 대충 이런말이다.
sing flag(SF)가 1이 아니라면, elseIfZero로 점프한다. if문의 조건(balanced <0)은 거짓이 된다.
9월 9일 어셈블리 jmp문과 loop문 cycle (0) | 2013.09.09 |
---|---|
8월 28일 어셈블리 mul, imul,연습문제 (0) | 2013.08.29 |
3월 28일 inc, dec, neg (0) | 2013.08.29 |
8월 27일 실습2(정리중) (0) | 2013.08.27 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
2*((length*width)+(length*height)+(width*height))를 어셈블리로 구하기
아래소스는 메모리 변수를 3개나 써서 구현한거.
.386 |
메모리 여기서는 변수를 사용하면, cycle이 느려서 컴파일이 느리다. 그래서 같은 결과의 소스라도 어셈브리는 최적화가
관건이다. 그래서 어셈블리가 어렵다. 필자가 작성한 소스는 완전한 최적하가 아니다. 배우는 단계라서 조금 더 공부하고
올릴예정이다.
9월 9일 어셈블리 jmp문과 loop문 cycle (0) | 2013.09.09 |
---|---|
9월 4일 conditional jump (0) | 2013.09.04 |
3월 28일 inc, dec, neg (0) | 2013.08.29 |
8월 27일 실습2(정리중) (0) | 2013.08.27 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
inc = +1증가 명령어
dec=-1증감 명령어
해당 operland는 한 개. 레지스터16,32를 (ex:eax, ax,...)을 쓸수 있고 변수를 선언하여 메모리로 operland로 사용가능.
inc register16/ register32
// memory byte/word/dword
dec도 inc와 동일하다.
neg 명령어
위의 표와 같이 operland는 한 개. 레지스터와 메모리를 operland로 쓸 수 있으며, neg명령어를 사용하면, 해당문자에
부호(-)를 붙인다. 예를 들어서 eax의 값이 100이라면, neg eax를 수행하면, -100이 된다.
다음그림은 예제 소스, 각각, add와 sub를 이용하여 사칙연산하는 어셈브리어이다.
C언어는 참 간단했었는데 어셈블리는 정말 어려운거라고 실감했다.
386 |
9월 4일 conditional jump (0) | 2013.09.04 |
---|---|
8월 28일 어셈블리 mul, imul,연습문제 (0) | 2013.08.29 |
8월 27일 실습2(정리중) (0) | 2013.08.27 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
어셈블리 디버깅(수정중) (0) | 2013.08.23 |
어큐물레이터
prefix
아래 그림은 xchg명령어 그림.
아래 그림은 잘못된 예
2개의 메모리가 사용되었기 때문에 잘못된 예이다. 메모리에서 메모리로 값을 집어넣을 수 없다.
어셈블리는 반드시 메모리->cpu->메모리를 거쳐야 된다. 아래 2두줄이 그 예가 되겠다.
아래 그림은 xchg 두 수를 스왑하는 명령어이다. xchg를 사용하지 않으면 밑에 mov명령어처럼 3줄을
써야한다. 이 중에서 어떤것이 최적화되고 사용하기 좋은가(?)라는 질문을 한다면, 컴파일러의 속도가 빠른것을
사용하는 것이 좋다.
일단, xchg명령어를 보면, timing386(386기준으로 속도, 주기)가 3주기가 된다.
그런데 아래 빨간색 mov명령어를 보면 timing386주기가 2주기. 명령어를 3줄썼으므로 6주기가 된다.
주기가 작을 수록 속도가 빠르기에 두 수를 스왑할 일이 생긴다면, xchg를 사용하는 것이 좋다.
아래 그림을 참조해서 본다면, memory가 reg보다 주기가 2배나 느리다는 것을 알 수 있다.
아래 그림은 엑셀 파일로 EFLAGS를 구성해본 그림. 아래 PDF에서는 OF, SF, ZF, CF를 모니터링 하고 있다.
SF=1이라면, 음수라고 생각하면 된다. 0이면 음수가 아니다.
ZF=계산 결과가 0이라면, 1이 된다.
CF=carry가 발생하면 1, 아니면, 0이다.
OF=1이라면, overflow
77ac와 4b35를 어셈블리어로 빼서 디버깅하였다. 그랬더니 efl이 16진수로 a96이 나왔다. 이것을 2진수로 반환하여
아래 그림과 같이 EFLAGS구조를 만들어 비교해보았다. 그랬더니, OF=1, SF=1, ZF=0, CF=0이 나왔다.
overflow와 음수인것을 의미한다.
아래그림은 pdf의 그림. 위 그림과 비교.
아래는 디버깅한 부분. Dbl을 예로 들어봤다. EFL레지스터가 헥사값으로 206이다. 이것을 2진수로 변환하여 위의 두그림처럼, 비교하여 CF,SF,ZF,OF가 pdf와 일치하는지 보았다.
8월 28일 어셈블리 mul, imul,연습문제 (0) | 2013.08.29 |
---|---|
3월 28일 inc, dec, neg (0) | 2013.08.29 |
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
어셈블리 디버깅(수정중) (0) | 2013.08.23 |
8월 21일 어셈블리 기본2. (0) | 2013.08.21 |
디버그 모드로 실행.
mov ebx, 1000
bb e8 03 00 00
pdf의 appendix를 참고하여 opcode를 찾으면 bb가 나온다.
아래 그림은 레지스터 값이다. 현재 eax는 헥사값 3e8(1000)이다. 지금 레지스터는 big endian형태로
되어 있다. 그러나 위의 메모리 상에는 little endian으로 되어 있다는 것을 유의하자.
3월 28일 inc, dec, neg (0) | 2013.08.29 |
---|---|
8월 27일 실습2(정리중) (0) | 2013.08.27 |
어셈블리 디버깅(수정중) (0) | 2013.08.23 |
8월 21일 어셈블리 기본2. (0) | 2013.08.21 |
8월 20일 disassembly(디스어셈블리) 약간 (0) | 2013.08.20 |
어셈블리는 숫자뒤에 h, b,o 또는 q를 붙이면, 각각 16진수, 10진수, 8진수를 나타낸다.
아래 그림을 참고한다.
(10진수는 아무것도 안적으면 된다. 마이크로소프트에서 어셈블리는 대소문자 구별안함. 다른 운영체제는 구별함.)
보충설명. 따옴표 ' '안에 있는 m은 m의 아스키코드를 나타낸다. 반대로 6d는 헥사값으로 m의 아스키 코드값이다.
결론은 char1과 char2는 똑같은 문장이다.
그리고 밑에 string1, string2를 유심히 보면, "joe"는 3바이트 "joe's"는 5바이트이다. 옆에 주석문 참고.
"joe's"는 안에 '까지 포함한다.
아래 그림에 stars는 1바이트형 50바이트까지 확보, 그리고 DUP '*'를 50개를 넣는다. 복사하다.(duplication)
starswAndSpaces는 공백까지 포함하여 *가 들어간다. 즉, * * * * ......이렇게 12개 그리고 마지막 널 자리에 *가
들어간다. 공간은 총 25바이트
아래 3개의 변수는 모두 144를 나타낸다. (참고로 word는 2바이트형)
어셈블리는 기본적으로 연산을 하고 실행되기 때문에 144를 적든, 12*12를 적은 똑같다.
QWORD는 8바이트.
TBYTE는 10바이트.
opcode= 기계어
number of bytes =바이트 수
timing 386 = 386에서의 주기
tuming 486=486에서의 주기
timing pentium=펜티엄에서의 주기
예를 들어 2개의 코드를 예를 들어 보았다.
1. mov al, '/'
mnemonic이 mov,
operrand가 al, imm8은 8비트크기의 상수.
flags affected는 모름(죄송)
opcode는 B0,
바이트수 2바이트 (B0, '/'를 아스키코드로 변환하면, 2F가 된다. 그래서 B0 2F의 크기의 2바이트)
386에서는 어셈블리 실행속도가 2주기, 486과 펜티엄은 1주기가 된다. 속도가 훨씬 빠르다.
2. add eax, number1
operland의 eax는 레지스터 32, number1은 변수로서 memory location 32bit 4바이트가 된다.
(원래는 eax, mem32를 찾으려 했으나, 없다. --, 없는 경우에 reg32, mem32를 찾아서 분석하자!!)
이 코드에서 잘보면, opcode까지는 별다른 이상이 없다. 그런데 바이트 수가 2+이다. 이것은 최소 2바이트 이상의
크기를 갖는다는 의미가 된다.
먼저,
|
단, 생략이 가능한 경우가 있다.
add edx, [eax]의 코드가 정상적으로 실행되었다고 가정한다면, 그것은
operland 중의 edx의 크기가 이미 알고있거나 정해진코드이기 때문에 굳이
자료형과 ptr을 쓰지 않고 []만 쳐도 상관없다.
8월 19일 어셈블리 기초이론1. (0) | 2013.08.19 |
---|
8월 27일 실습2(정리중) (0) | 2013.08.27 |
---|---|
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
8월 21일 어셈블리 기본2. (0) | 2013.08.21 |
8월 20일 disassembly(디스어셈블리) 약간 (0) | 2013.08.20 |
8월 19일 어셈블리 기본1. (0) | 2013.08.19 |
eax=(edx+ecx)-(ebx-eax);
를 어셈블리로 짠 소스.
add edx, ecx
sub ebx, eax
sub edx, ebx
mov eax, edx
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
---|---|
어셈블리 디버깅(수정중) (0) | 2013.08.23 |
8월 20일 disassembly(디스어셈블리) 약간 (0) | 2013.08.20 |
8월 19일 어셈블리 기본1. (0) | 2013.08.19 |
8월 14일 어셈블리(대충 흐름만 보기) (0) | 2013.08.16 |
C코드
아래는 디스어셈블리 코드
mov 대입 '='의미.
dword ptr [a]
dword= 4바이트.
[a]= 변수 'a'
ptr은 포인터와 비슷한 의미. 여기서는 a의 주소에 헥사값 64를 a에 대입한다.
64h =100의 헥사값. (100의 16진수)
add eax, 1
add는 '더한다'라는 명령어. 여기서는 eax에 1을 더한다는 의미. 즉, c코드로 생각하면, a=a+1
eax=eax+1이 되겠다.
++a와 a++은 어셈블리코드로 보면, 똑같다. 실제 컴파일 하는 속도는 ++a와 a++는 차이가 없다는 것을
알 수 있다.
a=b+a;
1. mov eax, dword ptr [b]= eax에 b를 대입하겠다는 의미. a와 b는 메모리 상에서 존재한다. 연산은 cpu만이
할 수 있으므로 먼저 cpu에서 메모리로부터 가져와서 임시저장공간 eax에 넣는다.
2. add eax, dword ptr[a]= eax와 a를 더한다. 당연히 cpu가 연산한다. (연산은 ALU 레지스터가 담당)
3. mov dword ptr[a], eax= eax는 지금 b+a를 연산한 결과값을 cpu가 지니고 있다. 이 결과값을 다시 메모리
에 있는 'a'라는 변수가 있는 메모리 주소에 보낸다. 그래서 이 3번째 코드가 없다면, 연산은 하지만, 연산한 결과
값은 나타나지 않는다.
b=a;
mov eax, dword ptr[a]= 'a'라는 변수를 eax에 대입한다.
mov dword ptr[b], eax= eax(a가 가지고 있는 값)를 메모리상에 존재하는 'b'에 대입한다.
8월 27일 디버깅을 이용한 opcode분석 (0) | 2013.08.27 |
---|---|
어셈블리 디버깅(수정중) (0) | 2013.08.23 |
8월 21일 어셈블리 기본2. (0) | 2013.08.21 |
8월 19일 어셈블리 기본1. (0) | 2013.08.19 |
8월 14일 어셈블리(대충 흐름만 보기) (0) | 2013.08.16 |