수업 노트 - 어셈블리어
- 노트필기/기타
- 2022. 2. 8.
개인적인 참고 용도입니다
- 1 의 보수 : 0 은 1 로 , 1 은 0 으로 변경 ( 00000100 → 11111011)
- 2 의 보수 : 1 의 보수에서 1 을 더한 값 ( 11111011 → 11111100)
스택
- 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역
- 높은 주소에서 낮은 주소로 신장
- LIFO 구조 : 가장 처음에 들어간 데이터가 가장 나중에 나옴
힙
- 동적으로 메모리 할당 시 사용하는 영역
- 낮은 주소에서 높은 주소로 신장
데이터 타입, 데이터 크기
비트 (bit): 0 또는 1
바이트 (byte): 8 비트
워드 (word): 16 비트
더블 워드 (dword): 32 비트 ( ARM 아키텍처에서는 워드)
쿼드 워드 : 64 비트 ( ARM 아키텍처에서는 더블워드)
x86
레지스터
빠른 연산을 위해 사용되는 레지스터 수행 문맥 , 제어 정보 , 데이터 임시 저장
레지스터는 CPU 에 내장된 저장 공간으로 , CPU 아키텍처마다 다름
<달고나 문서의 범용 레지스터 설명>
* 플래그 레지스터는 값을 바꾸는 명령어가 정해져 있음
x86 CPU의 기본 구조인 IA-32
"명령어 + 인자" 형태
명령어 : opcode (ex mov, push)
인자 : operand
push 337
mov eax, 1
-> eax에 1을 넣으라
-> 옵코드 mov 오퍼랜드는 eax와 1 (앞이 목적지, 뒤가 출발지)
EAX - Accumulator. 산술계산을 하며 리턴값을 전달
EDX - Data. EAX와 역할은 같으나 리턴 값의 용도로 사용되지 않음.
ECX - Count. 루프돌 때 카운트 역할. 0이 될때까지 감소하며 카운트
EBX - 레지스터가 부족하거나 할 때 알아서 사용
ESI (Source Index)
EDI (Destination Index)
명령어 세트
- 데이터 이동, 산수/논리 연산, 제어 흐름
참고자료
x86 Instruction Set Reference
NASM 프로그램 구조
지시자 : 코드에서 사용할 섹션 , 외부에서 참조할 함수 이름을 선언
명령어 : 어셈블리어 명령어 세트
피연산자 : 메모리 , 레지스터 , 데이터
섹션 : 하나의 작업을 위한 어셈블리어 코드 모음
PUSH, POP
스택에 값 넣기 가져오기 -> 오퍼랜드는 한개만 있으면 됨
push eax, push 1 등
MOV
mov eax, 1 -> eax에 1 넣기
LEA
주소를 가져오기
ADD
src에서 dest로 값 더하기
SUB
빼기
INT
인터럽트 일으키기
CALL
함수 호출 -> 오퍼랜드 뒤에 번지가 붙음. 해당 번지를 호출하고 작업이 끝나면 CALL 다음 번지로 돌아온다 왜냐하면 CALL로 호출된 코드 안에서는 반드시 RET를 만나 돌아옴
80x86 은 서브프로그램을 빠르고 간편하게 호출하기 위해서 스택을 이용한 2 가지 의 명령을 지원한다. CALL 명령은 서브프로그램으로의 무조건 분기를 한 후, 그 다음에 실행될 명령의 주소를 스택에 푸시(push)한다. RET 명령은 그 주소를 팝(pop) 한 후 그 주소로 점프를 한다. 이 명령을 이용할 때, 스택을 정확하게 관리하여 RET 명령에 의해
정확한 주소 값이 팝 될 수 있도록 해야 한다.
INC, DEC
INC는 i++ DEC는 i--
AND, OR, XOR
dest와 src를 연산함
XOR은 dest와 src를 동일한 오퍼랜드로 처리 가능. -> XOR EAX, EAX 실행하면 EAX가 0으로 초기화
NOP
아무것도 하지 말라
CMP, JMP
비교해서 점프하는 명령어
RETN
함수의 호출규약
호출자가 변수를 피호출자에게 넘기고 , 피호출자의 작업 결과를 반환하는 방법을 정의한 규약
항상 call 문의 당므 줄을 살펴서 스택을 정리하는 곳이 있는지 확인해야 함.
add esp, 8과 같이 스택을 보정하는 코드가 등장하면 __cdecl
__cdecl -> 함수 밖에서 스택 보정
cdecl(←C declaration)은 C 프로그래밍 언어가 기원인 호출 규약으로서 x86 아키텍처용의 수많은 C 컴파일러가 사용한다. (위키피디아)
__stdcall
stdcall 호출 규약은 마이크로소프트 Win32 API 및 오픈 왓콤 C++의 표준 호출 규약이다. 파스칼 호출 규약의 변형으로서 피호출자는 스택을 정리하는 일을 하지만 매개변수는 _cdecl 호출 규약에서처럼 오른쪽에서 왼쪽 순으로 스택 위로 푸시된다. 레지스터 EAX, ECX, EDX는 함수 내에 사용되도록 규정된다. 반환값은 EAX 레지스터에 저장된다. (위키피디아)
__fastcall
파라미터가 2개 이하일 경우 인자를 push로 넣지 않고 ecx와 edx 레지스터를 이용
함수 호출 전에 edx와 ecx에 값을 넣는 것이 보이면 __fastcall 규약 함수
__thiscall
주로 C++에서 이용. 현재 객체의 포인터를 ecx에 전달
ecx+x
ecx+y
ecx+z
* 보통 함수의 초반부에 레지스터를 push 문으로 스택에 넣는 코드가 등장한다면 앞으로 이 레지스터를 이 함수에서 계속 연산 목적으로 사용하려고 기존 값을 보관해두는 것
예제
hello_world.asm
extern printf
global main
section .data
message db "hello, world!", 10, 0
section .text
main:
push dword message
call printf
mov eax, 1
mov ebx, 0
int 80h
nasm -felf32 hello_world.asm && ld -I/lib/ld-linux.so.2 -lc --entry main hello_world.o
컴파일, 링킹 후 실행 결과
ld 명령어로 링크
objdump
objdump -d > 디스어셈블
PUSH 스택에 데이터를 삽입
ESP가 자동으로 4 바이트 감소
POP은 스택에서 데이터를 꺼냄
자동으로 ESP 4바이트 증가
gdb a.out으로 gdb 실행
disassemble main 혹은 disas main
AT&T에서 인텔 형식으로 변경
set disassembly-flavor intel
b main
으로 브레이크 포인트 걸기
EIP 는 0x08048060을 가리키고 있고 아직 해당 라인을 실행하지 않음
(gdb) disas main
Dump of assembler code for function main:
=> 0x08048060 <+0>: push 0x10
0x08048062 <+2>: push 0x12345678
0x08048067 <+7>: pop eax
0x08048068 <+8>: pop ebx
End of assembler dump.
(gdb) info reg
eax 0x0 0
ecx 0x0 0
edx 0x0 0
ebx 0x0 0
esp 0xbffff0a0 0xbffff0a0
ebp 0x0 0x0
esi 0x0 0
edi 0x0 0
eip 0x8048060 0x8048060 <main>
eflags 0x202 [ IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x0 0
ESP는 bffff0a0을 가리키고 있음
(gdb) info reg $eax
eax 0x0 0
(gdb) info reg $esp
esp 0xbffff0a0 0xbffff0a0
한줄만 실행
ni
(gdb) ni
0x08048062 in main ()
(gdb) info reg $esp
esp 0xbffff09c 0xbffff09c
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: push 0x10
=> 0x08048062 <+2>: push 0x12345678
0x08048067 <+7>: pop eax
0x08048068 <+8>: pop ebx
End of assembler dump.
(gdb) x/x $esp
0xbffff09c: 0x00000010
(gdb)
여러개 보기
(gdb) x/4x $esp
0xbffff09c: 0x00000010 0x00000001 0xbffff29d 0x00000000
(gdb) x/10x $esp
0xbffff09c: 0x00000010 0x00000001 0xbffff29d 0x00000000
0xbffff0ac: 0xbffff2b8 0xbffff2c3 0xbffff2d8 0xbffff2ef
0xbffff0bc: 0xbffff301 0xbffff331
x/x <- data
x/s <- string
x/x <- instruction
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: push $0x10
0x08048062 <+2>: push $0x12345678
=> 0x08048067 <+7>: pop %eax
0x08048068 <+8>: pop %ebx
End of assembler dump.
(gdb) x/4x $esp
0xbffff098: 0x12345678 0x00000010 0x00000001 0xbffff29d
(gdb) info registers $esp
esp 0xbffff098 0xbffff098
esp가 가리키는 곳에 12345678이 들어가 있음
(gdb) x/4x $esp
0xbffff09c: 0x00000010 0x00000001 0xbffff29d 0x00000000
(gdb) x/x 0xbffff098
0xbffff098: 0x12345678
(gdb) info reg $esp
esp 0xbffff09c 0xbffff09c
(gdb) info reg $eax
eax 0x12345678 305419896
Segmentation Fault in Linux
HINT: X86 어셈블리 언어는 가변 길이 명령어
프로그램이 허용되지 않은 메모리 영역에 접근을 시도하거나 , 잘못된 방법으로 메모리 영역에 접근을 시도할 경우 발생
우리 프로그램의 문제는 바로 끝맺음 을 제대로 하지 않은 것
GDB 에서 보면 다음 실행할 명령어 를 제대로 찾지 못하는 것을 확인 가능
프로그램의 끝은 시스템 콜을 이용해야 함
x/bx 1바이트
x/wx 4바이트 워드
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: push 0x10
0x08048062 <+2>: push 0x1234
=> 0x08048067 <+7>: mov eax,ebx
0x08048069 <+9>: mov ebx,0xbffff098
0x0804806e <+14>: mov DWORD PTR [ebx],0x10
0x08048074 <+20>: mov ebx,eax
End of assembler dump.
(gdb) x/4x $esp
0xbffff098: 0x00001234 0x00000010 0x00000001 0xbffff29d
(gdb) info reg $ebx
ebx 0x0 0
(gdb) info reg $eax
eax 0x0 0
(gdb) ni
0x08048069 in main ()
(gdb) ni
0x0804806e in main ()
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: push 0x10
0x08048062 <+2>: push 0x1234
0x08048067 <+7>: mov eax,ebx
0x08048069 <+9>: mov ebx,0xbffff098
=> 0x0804806e <+14>: mov DWORD PTR [ebx],0x10
0x08048074 <+20>: mov ebx,eax
End of assembler dump.
(gdb) info rege $ebx
Undefined info command: "rege $ebx". Try "help info".
(gdb) info regi $ebx
ebx 0xbffff098 -1073745768
(gdb) x/x 0xbffff098
0xbffff098: 0x00001234
(gdb) ni
0x08048074 in main ()
(gdb) x/x 0xbffff098
0xbffff098: 0x00000010
(gdb) info reg $ebx
ebx 0xbffff098 -1073745768
(gdb) ni
0x08048076 in ?? ()
ebx가 가리키는 곳에다가 10을 집어넣음
linux system call number
exit number
linux system call number
eax, 1
ebx, 0
int 80h
r/m32 주소 형식 - 대괄호 사용
MOV: 복사
- 레지스터 → 레지스터
- 메모리 ↔ 레지스터
- Immediate 값 → 레지스터 또는 메모리
- 메모리 ↔ 메모리는 안됨
ADD: 더하기 / SUB: 빼기
목적지는 r/m32 또는 레지스터
출발지는 r/m32 또는 레지스터 또는 상수값
출발지와 목적지가 모두 r/m32 일 수는 없음 -> 메모리 to 메모리는 안됨
OF, SF, ZF, AF, PF, CF 에 영향
LEA: 복사 (Load Effective Address 유효 주소 로드)
출발지는 r/m32
목적지는 레지스터
레지스터 연산 결과를 레지스터에 저장 (not 포인터)
MOV 와 무엇이 다른가
MOV 는 값을 로드하고 mov eax, [ebp+esp+4]
LEA 는 유효 주소를 로드한다 lea eax, [ebp+esp+4]
무브에서 대괄호를 쓰는 거는 연산 결과가 가르키는 주소에 있는 값을 넘김
LEA는 연산결과 값 자체를 넣겠다
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov eax,0x1
0x08048065 <+5>: mov ebx,0x4
0x0804806a <+10>: mov ecx,0x7
=> 0x0804806f <+15>: lea eax,[eax+ecx*1]
0x08048072 <+18>: lea ebx,[ebx*4+0x0]
0x08048079 <+25>: mov eax,DWORD PTR [eax+ecx*1]
End of assembler dump.
(gdb) ni
0x08048072 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov eax,0x1
0x08048065 <+5>: mov ebx,0x4
0x0804806a <+10>: mov ecx,0x7
0x0804806f <+15>: lea eax,[eax+ecx*1]
=> 0x08048072 <+18>: lea ebx,[ebx*4+0x0]
0x08048079 <+25>: mov eax,DWORD PTR [eax+ecx*1]
End of assembler dump.
(gdb) info reg $eax
eax 0x8 8
(gdb) info reg $ebx
ebx 0x4 4
(gdb) info reg $ecx
ecx 0x7 7
(gdb) ni
0x08048079 in main ()
(gdb) info reg $ebx
ebx 0x10 16
(gdb) ni
Program received signal SIGSEGV, Segmentation fault.
0x08048079 in main ()
(gdb) x/x 0x00000008
0x8: Cannot access memory at address 0x8
AND: 두 비트가 모두 1 일 때만 1
목적지는 r/m32 또는 레지스터
출발지는 r/m32 또는 레지스터 또는 상수값
OF, CF SF, ZF, PF
OR: 두 비트 중 하나라도 1 이면 1
목적지는 r/m32 또는 레지스터
출발지는 r/m32 또는 레지스터 또는 상수값
OF, CF SF, ZF, PF
XOR: 두 비트가 다를 때만 1
목적지는 r/m32 또는 레지스터
출발지는 r/m32 또는 레지스터 또는 상수값
OF, CF SF, ZF, PF
•
XOR 은 리버싱에서 유용하게 쓰여요
eax: 0x33 - 00110011
ebx : 0x55 - 01010101
ecx : 0x42 - 01000010
나머지 0xac - 10101100
eax and ebx -> 00010001
-> eax 값이 00010001로 바뀜
새 eax or ecx -> 01010011 -> 0x53
-> eax 값이 01010011로 바뀜
새새eax xor 0xac -> 11111111 -> 0xFF
End of assembler dump.
(gdb) b *main+15
Breakpoint 1 at 0x804806f
(gdb) r
Starting program: /home/x86_exam/exam4/a.out
Breakpoint 1, 0x0804806f in main ()
(gdb) info reg $eax
eax 0x33 51
(gdb) info reg $ebx
ebx 0x55 85
(gdb) ni
0x08048071 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov eax,0x33
0x08048065 <+5>: mov ebx,0x55
0x0804806a <+10>: mov ecx,0x42
0x0804806f <+15>: and eax,ebx
=> 0x08048071 <+17>: or eax,ecx
0x08048073 <+19>: xor eax,0xac
End of assembler dump.
(gdb) info reg $eax
eax 0x11 17
(gdb) ni
0x08048073 in main ()
(gdb) info reg $eax
eax 0x53 83
(gdb) ni
0x08048078 in ?? ()
Program received signal SIGSEGV, Segmentation fault.
0x08048078 in ?? ()
(gdb) info reg $eax
eax 0xff 255
•
INC: 피연산자의 값을 1 증가시킴
OF, SF, ZF, AF, PF 에 영향
DEC: 피연산자의 값을 1 감소시킴
OF, SF, ZF, AF, PF 에 영향
•
CMP: 두 값을 비교
cmp 레지스터 , 상수값
cmp r/m32, 상수값
cmp r/m32, 레지스터
cmp 레지스터 , r/m32
출발지에서 목적지 값을 뺀 결과를 플래그에 반영
결과는 버림
TEST: 논리 비교
test eax, eax ( eax 값이 0 인 경우 ZF=1 )
보통 jcc 랑 같이 쓰임
제어 흐름
조건부 제어 : IF, WHILE, SWITCH
비조건부 제어 : CALL, GOTO, EXCEPTION, INTERRUPT
•
JMP: Jump!
피연산자 주소로 EIP 를 변경
Short Jump(OF 85): 현재 EIP 값에서 128~127 범위로 이동
Far Jump(75): 다른 세그먼트에 위치한 명령어로 이동
JCC: Jump if Condition Is Met
특정 조건을 만족할 경우 지정한 주소로 제어 흐름을 이동
JNE: Jump Not Equal (ZF=0)
JE: Jump Equal (ZF=1)
JLE: Jump Less Equal (ZF=1 or SF<>OF)
CALL: 함수 호출
call printf / 0x80480000 / [eax + 4]
우선 다음 실행할 명령어 주소를 스택에 삽입한 뒤 EIP에 해당 주소를 옮긴 뒤 이동하는 방식외부 함수를 사용하는 경우 반드시 해당 함수가 포함된 라이브러리를 linker 에 함께 전달해야 함
IF Flag
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov eax,0x2
=> 0x08048065 <+5>: cmp eax,0x2
0x08048068 <+8>: cmp eax,0x1
0x0804806b <+11>: cmp eax,0x3
0x0804806e <+14>: test eax,eax
0x08048070 <+16>: mov eax,0x0
0x08048075 <+21>: test eax,eax
End of assembler dump.
(gdb) info reg $eflags
eflags 0x202 [ IF ]
(gdb) info reg $eax
eax 0x2 2
(gdb) ni
0x08048068 in main ()
(gdb) info reg $eflags
eflags 0x246 [ PF ZF IF ]
2와 2를 비교해서
PF, ZF 세팅됨
PF 연산 결과의 비트 개수에 따라 세팅 -> 여기 짝수
ZF 결과가 0이라 세팅됨
(gdb)
eflags 0x246 [ PF ZF IF ]
(gdb) ni
0x0804806b in main ()
(gdb) info reg $eflags
eflags 0x202 [ IF ]
(gdb) ni
0x0804806e in main ()
(gdb) info reg $eflags
eflags 0x297 [ CF PF AF SF IF ]
(gdb)
2-1 하면 양수니까 아무것도 세팅이 안됨 IF
2-3 하면 음수가 되니 많이 설정됨 CF PF AF SF IF
- CF 숫자가 부족하다 - 결과가 음수일 경우 ->앞에 숫자 빌려옴(캐리)
- AF 하위 비트에서 캐리가 발생할 경우
- SF 음수
(gdb) info reg $eax
eax 0x2 2
(gdb) info reg $eflags
eflags 0x297 [ CF PF AF SF IF ]
(gdb) ni
0x08048070 in main ()
(gdb) info reg $eflags
eflags 0x202 [ IF ]
(gdb) info reg $eax
eax 0x2 2
(gdb) ni
0x08048075 in main ()
(gdb) info reg $eflags
eflags 0x202 [ IF ]
(gdb) ni
0x08048077 in ?? ()
(gdb) info reg $eflags
eflags 0x246 [ PF ZF IF ]
eax 값이 0이기 때문에 ZF (Zeroflag) 세팅됨
global main
section .text
main:
mov ecx, 0
mov eax, ecx
inc ecx
cmp ecx, 255
root@stud:/home/x86_exam/exam6# objdump -d a.out
a.out: file format elf32-i386
Disassembly of section .text:
08048060 <main>:
8048060: b9 00 00 00 00 mov $0x0,%ecx
8048065: 89 c8 mov %ecx,%eax
8048067: 41 inc %ecx
8048068: 81 f9 ff 00 00 00 cmp $0xff,%ecx
root@stud:/home/x86_exam/exam6# vi exam6.asm
root@stud:/home/x86_exam/exam6# gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov $0x0,%ecx
0x08048065 <+5>: mov %ecx,%eax
0x08048067 <+7>: inc %ecx
0x08048068 <+8>: cmp $0xff,%ecx
End of assembler dump.
c는 다음 브레이크포인트까지 실행
jne 코드 추가
(gdb) disas main
Dump of assembler code for function main:
0x08048060 <+0>: mov ecx,0x0
0x08048065 <+5>: mov eax,ecx
0x08048067 <+7>: inc ecx
0x08048068 <+8>: cmp ecx,0xff
=> 0x0804806e <+14>: jne 0x8048067 <main+7>
End of assembler dump.
(gdb) info reg $ecx
ecx 0x1 1
(gdb) c
Continuing.
Breakpoint 1, 0x0804806e in main ()
(gdb) info reg $ecx
ecx 0x2 2
(gdb) c
Continuing.
Breakpoint 1, 0x0804806e in main ()
(gdb) info reg $ecx
ecx 0x3 3
난독화 코드 만들기
section .data
message db "hello world", 10, 0
아스키에서 10은 개행문자, 0은 끝이라는 뜻
global main
extern printf
section .data
message db "hello world", 10, 0
section .text
main:
push dword message
mov eax, [esp]
mov ecx, 11
jmp loop1
loop1:
xor [eax+ecx-1], byte 0x33
dec ecx
jne loop1
push dword message
call printf
0x64 xor 0x33 -> 0x57
root@stud:/home/x86_exam/obfus# ./a.out
[V__\D\A_W
Segmentation fault (core dumped)
root@stud:/home/x86_exam/obfus# vi obfus.asm
root@stud:/home/x86_exam/obfus# gdb -q a.out
Reading symbols from a.out...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048190 <+0>: push 0x8049264
0x08048195 <+5>: mov eax,DWORD PTR [esp]
0x08048198 <+8>: mov ecx,0xb
0x0804819d <+13>: jmp 0x804819f <loop1>
End of assembler dump.
(gdb) disas loop1
Dump of assembler code for function loop1:
0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
0x080481a5 <+6>: jne 0x804819f <loop1>
0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
(gdb) x/x 0x8049264
0x8049264: 0x6c6c6568
(gdb) x/s 0x8049264
0x8049264: "hello world\n"
(gdb) disas main
Dump of assembler code for function main:
0x08048190 <+0>: push 0x8049264
0x08048195 <+5>: mov eax,DWORD PTR [esp]
0x08048198 <+8>: mov ecx,0xb
0x0804819d <+13>: jmp 0x804819f <loop1>
End of assembler dump.
(gdb) b *main
Breakpoint 1 at 0x8048190
(gdb) r
Starting program: /home/x86_exam/obfus/a.out
Breakpoint 1, 0x08048190 in main ()
(gdb) disas m
No symbol "m" in current context.
(gdb) disas main
Dump of assembler code for function main:
=> 0x08048190 <+0>: push 0x8049264
0x08048195 <+5>: mov eax,DWORD PTR [esp]
0x08048198 <+8>: mov ecx,0xb
0x0804819d <+13>: jmp 0x804819f <loop1>
End of assembler dump.
(gdb) ni
0x08048195 in main ()
(gdb) x/4x $esp
0xbffff09c: 0x64 0x92 0x04 0x08
(gdb) x/4wx $esp
0xbffff09c: 0x08049264 0x00000001 0xbffff29d 0x00000000
(gdb) ni
0x08048198 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x08048190 <+0>: push 0x8049264
0x08048195 <+5>: mov eax,DWORD PTR [esp]
=> 0x08048198 <+8>: mov ecx,0xb
0x0804819d <+13>: jmp 0x804819f <loop1>
End of assembler dump.
(gdb) info eg &esp
Undefined info command: "eg &esp". Try "help info".
(gdb) info reg &esp
Invalid register `&esp'
(gdb) info reg $esp
esp 0xbffff09c 0xbffff09c
(gdb) info reg $eax
eax 0x8049264 134517348
(gdb) ni
0x0804819d in main ()
(gdb) ni
0x0804819f in loop1 ()
(gdb) disas loop1
Dump of assembler code for function loop1:
=> 0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
0x080481a5 <+6>: jne 0x804819f <loop1>
0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
(gdb) info reg $eax
eax 0x8049264 134517348
(gdb) info reg $ecx
ecx 0xb 11
(gdb) x/x 0x8049264+10
0x804926e: 0x00000a64
(gdb) x/s 0x8049264+10
0x804926e: "d\n"
(gdb) x/s 0x804926e
0x804926e: "d\n"
(gdb) x/s 0x804926d
0x804926d: "ld\n"
(gdb) x/s 0x804926c
0x804926c: "rld\n"
(gdb) x/s 0x804926b
0x804926b: "orld\n"
(gdb) x/s 0x804926a
0x804926a: "world\n"
(gdb) x/x 0x804926a
0x804926a: 0x77
(gdb) disas loop1
Dump of assembler code for function loop1:
=> 0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
0x080481a5 <+6>: jne 0x804819f <loop1>
0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
(gdb) ni
0x080481a4 in loop1 ()
(gdb) x/x 0x804926e
0x804926e: 0x57
(gdb) x/s 0x804926e
0x804926e: "W\n"
(gdb) ni
0x080481a5 in loop1 ()
(gdb) disassemble lopp1
No symbol "lopp1" in current context.
(gdb) disassemble loop1
Dump of assembler code for function loop1:
0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
=> 0x080481a5 <+6>: jne 0x804819f <loop1>
0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
(gdb) info reg $ecx
ecx 0xa 10
(gdb) info reg $eflags
eflags 0x206 [ PF IF ]
(gdb) ni
0x0804819f in loop1 ()
(gdb) disas loop1
Dump of assembler code for function loop1:
=> 0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
0x080481a5 <+6>: jne 0x804819f <loop1>
0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
(gdb) b *loop1+8
Breakpoint 2 at 0x80481a7
(gdb) c
Continuing.
Breakpoint 2, 0x080481a7 in loop1 ()
(gdb) x/s 0x8049264
0x8049264: "[V__\\\023D\\A_W\n"
(gdb) disas loop1
Dump of assembler code for function loop1:
0x0804819f <+0>: xor BYTE PTR [eax+ecx*1-0x1],0x33
0x080481a4 <+5>: dec ecx
0x080481a5 <+6>: jne 0x804819f <loop1>
=> 0x080481a7 <+8>: push 0x8049264
0x080481ac <+13>: call 0x8048180 <printf@plt>
End of assembler dump.
ARM
ARM 아키텍처 요약
- 데이터 타입 : 어셈블리 기본
- 주소 표기법 : 명령어는 리틀 엔디언 , 데이터는 혼합 사용
- 레지스터 : 13 개의 범용 레지스터 , 3 개의 특수 레지스터
- 명령어 세트 : 고정 길이 명령어 형식을 사용
- 피연산자 : 레지스터 , 메모리 주소 , 주소값 , 숫자
- 기본 문법 : 모든 작업은 레지스터에서 수행 (Load/Store 구조
=>ARM은 레지스터가 중심이다!
Arm모드, Thumb 모드가 있고 주로 Arm 모드 사용.
PC는 다음 실행할 명령어
•
파이프
ARM 명령어를 실행할 때 PC 는 현재 명령어 8 위치한 명령어를 읽는다
Thumb 명령어는 현재 명령어 4 에 위치한 명령어를 읽는다
ARM은 명령어 수는 적지만 조건을 붙여서 여러 방식으로 사용 가능
ARM 실습을 위한 qemu 실행 명령어
qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.img-3.2.0-4-versatile -hda debian_wheezy_armel_standard.qcow2 -append "root=/dev/sda1" -chardev socket,path=/tmp/port1,server,nowait,id=port1-char -device virtio-serial -device virtserialport,id=port1,chardev=port1-char,name=org.port.0 -net user,hostfwd=tcp::10022-:22 -net nic
apt-get 키 오류날 때
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 1397BC53640DB551
ssh root@localhost -p10022
.global main
string:
.ascii "hello world\n"
main:
mov r0, #1
ldr r1, =string
mov r2, #12
mov r7, #4
swi 0
root@debian-armel:~/hello# ls
hello.s
root@debian-armel:~/hello# as hello.s
root@debian-armel:~/hello# as -o hello.o hello.s && ld -entry main hello.o
root@debian-armel:~/hello# ls
a.out hello.o hello.s
root@debian-armel:~/hello# ./a.out
hello world
Segmentation fault
root@debian-armel:~/hello#
MOV: 데이터 복사
32 비트 값을 레지스터로 복사
MVN: NOT 데이터 복사
32 비트 값의 NOT 을 레지스터로 복사
코드
.global main
main:
mov r5, #5
mov r7, $7
mvn r7, r5
mov r7, $7
mov r7, r5, lsl #2
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r5, #5
0x00008058 <+4>: mov r7, #7
0x0000805c <+8>: mvn r7, r5
0x00008060 <+12>: mov r7, #7
0x00008064 <+16>: lsl r7, r5, #2
End of assembler dump.
(gdb) b *main
Breakpoint 1 at 0x8054
(gdb) r
Starting program: /root/hello/exam1/a.out
Breakpoint 1, 0x00008054 in main ()
(gdb) disas main
Dump of assembler code for function main:
=> 0x00008054 <+0>: mov r5, #5
0x00008058 <+4>: mov r7, #7
0x0000805c <+8>: mvn r7, r5
0x00008060 <+12>: mov r7, #7
0x00008064 <+16>: lsl r7, r5, #2
End of assembler dump.
(gdb) info reg
r0 0x0 0
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffc90 0xbefffc90
lr 0x0 0
pc 0x8054 0x8054 <main>
cpsr 0x10 16
(gdb) ni
0x00008058 in main ()
(gdb) ni
0x0000805c in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r5, #5
0x00008058 <+4>: mov r7, #7
=> 0x0000805c <+8>: mvn r7, r5
0x00008060 <+12>: mov r7, #7
0x00008064 <+16>: lsl r7, r5, #2
End of assembler dump.
(gdb) info reg $r5
r5 0x5 5
(gdb) info reg $r7
r7 0x7 7
(gdb) ni
0x00008060 in main ()
(gdb) info reg $r7
r7 0xfffffffa 4294967290
mvn
00000101을 not 하면 11111010 -> 16 진수로 FA
mov r7, r5
r5에 5가 들어있는데 그걸 not해서 그 결과를 r7에 넣겠다
lsl -> r5값을 2만큼 쉬프트
00000101 ->쉬프트하면 00010100 -> 이게 r7에 들어감 20임
(gdb) ni
Cannot access memory at address 0x0
0x00008068 in ?? ()
(gdb) info reg $r7
r7 0x14 20
데이터 비교
CMN: 더하기 비교
cmn r0, r1 → r0 + r1
CMP: 빼기 비교
cmp r0, r1 → r0 r1
TEQ: 두 값이 같은지 비교 (xor)
teq r0, r1 → r0 ^ r1
TST: 비트 테스트 (and)
tst r0, r1 → r0 & r1
레지스터 비교 결과에 따라 CPSR 플래그 업데이트
.global main
main:
mov r0, #0
mov r1, #1
mov r2, #254,
cmp r0, r1
cmn r2, r2
tst r0, r0
teq r0, r1
cmp r0, #0
moveq r0, #2
moveq는 ZF 값에 따라 실행여부 결정
cpsr 기본값 10
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #0
0x00008058 <+4>: mov r1, #1
0x0000805c <+8>: mov r2, #254 ; 0xfe
=> 0x00008060 <+12>: cmp r0, r1
0x00008064 <+16>: cmn r2, r2
0x00008068 <+20>: tst r0, r0
0x0000806c <+24>: teq r0, r1
0x00008070 <+28>: cmp r0, #0
0x00008074 <+32>: moveq r0, #2
End of assembler dump.
(gdb) info registers
r0 0x0 0
r1 0x1 1
r2 0xfe 254
r3 0x0 0
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffc90 0xbefffc90
lr 0x0 0
pc 0x8060 0x8060 <main+12>
cpsr 0x10 16
(gdb) info reg $cpsr
cpsr 0x10 16
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #0
0x00008058 <+4>: mov r1, #1
0x0000805c <+8>: mov r2, #254 ; 0xfe
=> 0x00008060 <+12>: cmp r0, r1
0x00008064 <+16>: cmn r2, r2
0x00008068 <+20>: tst r0, r0
0x0000806c <+24>: teq r0, r1
0x00008070 <+28>: cmp r0, #0
0x00008074 <+32>: moveq r0, #2
End of assembler dump.
(gdb) ni
0x00008064 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #0
0x00008058 <+4>: mov r1, #1
0x0000805c <+8>: mov r2, #254 ; 0xfe
0x00008060 <+12>: cmp r0, r1
=> 0x00008064 <+16>: cmn r2, r2
0x00008068 <+20>: tst r0, r0
0x0000806c <+24>: teq r0, r1
0x00008070 <+28>: cmp r0, #0
0x00008074 <+32>: moveq r0, #2
End of assembler dump.
(gdb) info reg $cpsr
cpsr 0x80000010 -2147483632
(gdb) ni
0x00008068 in main ()
(gdb) info reg $cpsr
cpsr 0x10 16
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #0
0x00008058 <+4>: mov r1, #1
0x0000805c <+8>: mov r2, #254 ; 0xfe
0x00008060 <+12>: cmp r0, r1
0x00008064 <+16>: cmn r2, r2
=> 0x00008068 <+20>: tst r0, r0
0x0000806c <+24>: teq r0, r1
0x00008070 <+28>: cmp r0, #0
0x00008074 <+32>: moveq r0, #2
End of assembler dump.
(gdb) ni
0x0000806c in main ()
(gdb) info reg $cpsr
cpsr 0x40000010 1073741840
(gdb) ni
0x00008070 in main ()
(gdb) info reg $cpsr
cpsr 0x10 16
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #0
0x00008058 <+4>: mov r1, #1
0x0000805c <+8>: mov r2, #254 ; 0xfe
0x00008060 <+12>: cmp r0, r1
0x00008064 <+16>: cmn r2, r2
0x00008068 <+20>: tst r0, r0
0x0000806c <+24>: teq r0, r1
=> 0x00008070 <+28>: cmp r0, #0
0x00008074 <+32>: moveq r0, #2
End of assembler dump.
(gdb) ni
0x00008074 in main ()
(gdb) info reg $cpsr
cpsr 0x60000010 1610612752
(gdb) info reg $r0
r0 0x0 0
(gdb) ni
Cannot access memory at address 0x0
0x00008078 in ?? ()
(gdb) info reg $cpsr
cpsr 0x60000010 1610612752
(gdb) info reg $r0
r0 0x2 2
연산 결과에 따라서 플래그 값이 변경
cpsr을 이진수로 긁어서 봐야한다
위에 나온 플래그 설명 참조
점프는 돌아 오는 걸 가정하지 않음
Call은 서브루틴을 콜하는거라 돌아오게 되어있음
BL은 Call과 비슷하고 B는 Jmp와 비슷
.global main
main:
mov r0, #2
mov r1, #0
b loop
loop:
sub r0, r0, #1
cmp r0, r1
bne loop
mov r7, #1
swi 0
swi 0이 exit 역할
section과 function을 구분해야 할 필요가 있다
위의 main과 loop는 함수 호출 규약을 따르지 않기 때문에 섹션으로 보는 것이 맞음
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: mov r1, #0
0x0000805c <+8>: b 0x8060 <loop>
End of assembler dump.
(gdb) disas loop
Dump of assembler code for function loop:
0x00008060 <+0>: sub r0, r0, #1
0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) b *main+8
Breakpoint 1 at 0x805c
(gdb) r
Starting program: /root/hello/exam3/a.out
Breakpoint 1, 0x0000805c in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: mov r1, #0
=> 0x0000805c <+8>: b 0x8060 <loop>
End of assembler dump.
(gdb) ni
0x00008060 in loop ()
(gdb) disas loop
Dump of assembler code for function loop:
=> 0x00008060 <+0>: sub r0, r0, #1
0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) info reg $r0
r0 0x2 2
(gdb) info reg $r1
r1 0x0 0
(gdb) ni
0x00008064 in loop ()
(gdb) info reg $r0
r0 0x1 1
(gdb) info reg $cpsr
cpsr 0x10 16
(gdb) disas loop
Dump of assembler code for function loop:
0x00008060 <+0>: sub r0, r0, #1
=> 0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) ni
0x00008068 in loop ()
(gdb) info reg $cpsr
cpsr 0x20000010 536870928
(gdb) ^CQuit
(gdb) disas loop
Dump of assembler code for function loop:
0x00008060 <+0>: sub r0, r0, #1
0x00008064 <+4>: cmp r0, r1
=> 0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) ni
0x00008060 in loop ()
(gdb) info reg $cpsr
cpsr 0x20000010 536870928
(gdb) disas loop
Dump of assembler code for function loop:
=> 0x00008060 <+0>: sub r0, r0, #1
0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) ni
0x00008064 in loop ()
(gdb) disas loop
Dump of assembler code for function loop:
0x00008060 <+0>: sub r0, r0, #1
=> 0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) info reg $cpsr
cpsr 0x20000010 536870928
(gdb) ni
0x00008068 in loop ()
(gdb) info reg $cpsr
cpsr 0x60000010 1610612752
(gdb) ni
0x0000806c in loop ()
(gdb) disas loop
Dump of assembler code for function loop:
0x00008060 <+0>: sub r0, r0, #1
0x00008064 <+4>: cmp r0, r1
0x00008068 <+8>: bne 0x8060 <loop>
=> 0x0000806c <+12>: mov r7, #1
0x00008070 <+16>: svc 0x00000000
End of assembler dump.
(gdb) c
Continuing.
[Inferior 1 (process 8968) exited normally]
(gdb)
제로플래그 0될때까지 루프 돈다
Load-Store
지금까지는 x86과 유사했으나 이 경우에는 특이함
LD -> LoaD
ST -> STore
R은 레지스터
M은 멀티플(레지스터)로 이해
로드는 목적지가 무조건 레지스터. 출발지는 메모리 영역
대괄호 안에 있는 값만 영향을 받는다고 생각하면 됨(Post 인덱스는 R1에 대괄호 생략)
Post 인덱스는 목적지에 R0에 오프셋을 넣어주지 않음
ldr은 #대신 =사용해야 함
str은 ldr이랑 반대의 순서로 넣는다고 생각해야함. (앞에서 뒤로 감) r1에 있는 값을 r0에서 8떨어진 위치에 넣겠다
(gdb) disas main
Dump of assembler code for function main:
0x00008060 <+0>: mov r1, #255 ; 0xff
0x00008064 <+4>: mov r0, sp
0x00008068 <+8>: ldr r1, [pc, #-0] ; 0x8070 <main+16>
0x0000806c <+12>: str r1, [r0, #8]
0x00008070 <+16>: andeq r8, r0, r4, asr r0
End of assembler dump.
(gdb) q
root@debian-armel:~/exam4# cat exam4.s
.global main
string:
.ascii "hello world\n"
main:
ldr r1, =255
mov r0, r13
ldr r1, =string
str r1, [r0, #8]
main+0번줄
ldr 숫자가 특정 범위 안에 있는 값이면 mov로 바꿈 -> 굳이 메모리에서 가져올 필요 없음 -> 코드의 효율성
(gdb) disas main
Dump of assembler code for function main:
0x00008060 <+0>: mov r1, #255 ; 0xff
0x00008064 <+4>: mov r0, sp
=> 0x00008068 <+8>: ldr r1, [pc, #-0] ; 0x8070 <main+16>
0x0000806c <+12>: str r1, [r0, #8]
0x00008070 <+16>: andeq r8, r0, r4, asr r0
End of assembler dump.
(gdb) info reg $pc
pc 0x8068 0x8068 <main+8>
(gdb) x/x 0x00008070
0x8070 <main+16>: 0x00008054
(gdb) x/x 0x00008054
0x8054 <string>: 0x6c6c6568
(gdb) x/s 0x00008054
0x8054 <string>: "hello world\n\377\020\240\343\r"
(gdb)
string을 r1으로 옮기라고 했는데 pc 안에 있는 주소가 가리키는 곳의 데이터를 r1로 올기는 것으로 바뀜
arm은 sp가 다다음 명령어 가리킴 +8에서 pc는 8070 (다다음줄)
8070에는 8054라는 값이 있음 -> 임의로 adeq라는 명령으로 읽었지만 사실 값은 string임 (hello world)
(gdb) disas main
Dump of assembler code for function main:
0x00008060 <+0>: mov r1, #255 ; 0xff
0x00008064 <+4>: mov r0, sp
=> 0x00008068 <+8>: ldr r1, [pc, #-0] ; 0x8070 <main+16>
0x0000806c <+12>: str r1, [r0, #8]
0x00008070 <+16>: andeq r8, r0, r4, asr r0
End of assembler dump.
(gdb) ni
0x0000806c in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008060 <+0>: mov r1, #255 ; 0xff
0x00008064 <+4>: mov r0, sp
0x00008068 <+8>: ldr r1, [pc, #-0] ; 0x8070 <main+16>
=> 0x0000806c <+12>: str r1, [r0, #8]
0x00008070 <+16>: andeq r8, r0, r4, asr r0
End of assembler dump.
(gdb) info reg $r1
r1 0x8054 32852
(gdb) info reg $r0
r0 0xbefffcb0 3204447408
(gdb) ni
0x00008070 in main ()
(gdb) x/4x 0xbefffcb0
0xbefffcb0: 0x01 0x00 0x00 0x00
(gdb) x/4wx 0xbefffcb0
0xbefffcb0: 0x00000001 0xbefffdc9 0x00008054 0xbefffddb
(gdb) info reg $cpsr
cpsr 0x10 16
r0 ->0xbefffcb0
r0, #8 > 0xbefffcb8 >-요기에다가 r1-> 8054를 넣겠다
=> 0x0000806c <+12>: str r1, [r0, #8]
andeq는 비록 8054로 문자열이지만 제로플래그도 없어서 결국 실행되지 않음
느낌표는 연산 하고 나서 앞에 있는 거를 갱신시킨다
.global main
main:
mov r0, #2
str r0, [r13, #4]
add r0, r0, #1
str r0, [r13, #8]
mov r0, r13
(gdb) b* main
Breakpoint 1 at 0x8054
(gdb) r
Starting program: /root/exam5/a.out
Breakpoint 1, 0x00008054 in main ()
(gdb) disas main
Dump of assembler code for function main:
=> 0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
End of assembler dump.
(gdb) ni
0x00008058 in main ()
(gdb) info reg $r0
r0 0x2 2
(gdb) ni
0x0000805c in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
=> 0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
End of assembler dump.
(gdb) info reg $sp
sp 0xbefffcb0 0xbefffcb0
(gdb) x/4x $sp
0xbefffcb0: 0x00000001 0x00000002 0x00000000 0xbefffddb
(gdb) ni
0x00008060 in main ()
(gdb) info reg $r0
r0 0x3 3
(gdb) ni
0x00008064 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
=> 0x00008064 <+16>: mov r0, sp
End of assembler dump.
(gdb) x/x 0xbefffcb8
0xbefffcb8: 0x00000003
(gdb) x/4x $sp
0xbefffcb0: 0x00000001 0x00000002 0x00000003 0xbefffddb
(gdb) x/4x $sp
0xbefffcb0: 0x00000001 0x00000002 0x00000000 0xbefffddb
스택에 1은 원래 들어가있던거고 +4지점에 2를 넣은거임
수업 제대로 안들음- >필요시 다시 공부 필요...
강의제목 - ldm, stm 명령어
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) b *main+16
Breakpoint 1 at 0x8064
(gdb) r
Starting program: /root/exam5/a.out
Breakpoint 1, 0x00008064 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
=> 0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) x/4x 0xbefffcb0
0xbefffcb0: 0x00000001 0x00000002 0x00000003 0xbefffddb
(gdb) info reg $r0
r0 0x3 3
(gdb) ni
0x00008068 in main ()
(gdb) info reg $r0
r0 0xbefffcb0 3204447408
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
=> 0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) ni
0x0000806c in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
=> 0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) info reg
r0 0xbefffcbc 3204447420
r1 0x1 1
r2 0x2 2
r3 0x3 3
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x806c 0x806c <main+24>
cpsr 0x10 16
(gdb) x/x 0xbefffcbc
0xbefffcbc: 0xbefffddb
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
=> 0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) ni
0x00008070 in main ()
(gdb) info reg $r0
r0 0xbefffcb0 3204447408
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
=> 0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) ni
0x00008074 in main ()
(gdb) info reg
r0 0xbefffcbc 3204447420
r1 0x2 2
r2 0x3 3
r3 0xbefffddb 3204447707
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x8074 0x8074 <main+32>
cpsr 0x10 16
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
=> 0x00008074 <+32>: mov r0, sp
0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) ni
0x00008078 in main ()
(gdb) info reg
r0 0xbefffcb0 3204447408
r1 0x2 2
r2 0x3 3
r3 0xbefffddb 3204447707
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x8078 0x8078 <main+36>
cpsr 0x10 16
(gdb) x/x 0xbefffca4
0xbefffca4: 0x00000000
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r0, #2
0x00008058 <+4>: str r0, [sp, #4]
0x0000805c <+8>: add r0, r0, #1
0x00008060 <+12>: str r0, [sp, #8]
0x00008064 <+16>: mov r0, sp
0x00008068 <+20>: ldm r0!, {r1, r2, r3}
0x0000806c <+24>: mov r0, sp
0x00008070 <+28>: ldmib r0!, {r1, r2, r3}
0x00008074 <+32>: mov r0, sp
=> 0x00008078 <+36>: ldmda r0!, {r1, r2, r3}
0x0000807c <+40>: mov r0, sp
0x00008080 <+44>: ldmda r0!, {r1, r2, r3}
End of assembler dump.
(gdb) ni
0x0000807c in main ()
(gdb) nni
Undefined command: "nni". Try "help".
(gdb) ni
0x00008080 in main ()
(gdb) info reg
r0 0xbefffcb0 3204447408
r1 0x0 0
r2 0x0 0
r3 0x1 1
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x8080 0x8080 <main+44>
cpsr 0x10 16
(gdb) ni
Cannot access memory at address 0x0
0x00008084 in ?? ()
(gdb) info reg
r0 0xbefffca4 3204447396
r1 0x0 0
r2 0x0 0
r3 0x1 1
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x8084 0x8084
cpsr 0x10 16
R11-R9 바이트만큼 R10이 위치한 곳에 메모리를 복사하라(R9가 R11이 될때까지 올라감)
FD, ED 중요!
.global main
main:
mov r1, #10
mov r2, #20
mov r3, #30
mov r4, sp
stmdd sp!, {r1-r3}
eor r1, r1
eor r2, r2
eor r3, r3
ldmdb r4, {r1-r3}
stmdd -> r1~r3값을 스택포인트 가리키는 곳에 집어넣고, 디센딩이니까 스택포인트 낮추고 스택포인트에 갱신
eor -> r1,r2,r3를 모두 0으로 만듬
ldmdb 레지스터로 팝 r4가 가리키는 지점부터 시작해서 메모리 주소를 올리면서 r1~r3 값 넣음
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r1, #10
0x00008058 <+4>: mov r2, #20
0x0000805c <+8>: mov r3, #30
0x00008060 <+12>: mov r4, sp
0x00008064 <+16>: push {r1, r2, r3}
0x00008068 <+20>: eor r1, r1, r1
0x0000806c <+24>: eor r2, r2, r2
0x00008070 <+28>: eor r3, r3, r3
0x00008074 <+32>: ldmdb r4, {r1, r2, r3}
End of assembler dump.
stmfd가 push로 바뀜 (어차피 걍 스택포인트에 넣는 거라 푸쉬하는 거랑 같음)
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r1, #10
0x00008058 <+4>: mov r2, #20
0x0000805c <+8>: mov r3, #30
0x00008060 <+12>: mov r4, sp
0x00008064 <+16>: push {r1, r2, r3}
0x00008068 <+20>: eor r1, r1, r1
0x0000806c <+24>: eor r2, r2, r2
0x00008070 <+28>: eor r3, r3, r3
0x00008074 <+32>: ldmdb r4, {r1, r2, r3}
End of assembler dump.
(gdb) b *main+16
Breakpoint 1 at 0x8064
(gdb) r
Starting program: /root/exam6/a.out
Breakpoint 1, 0x00008064 in main ()
(gdb) info reg
r0 0x0 0
r1 0xa 10
r2 0x14 20
r3 0x1e 30
r4 0xbefffcb0 3204447408
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffcb0 0xbefffcb0
lr 0x0 0
pc 0x8064 0x8064 <main+16>
cpsr 0x10 16
(gdb) x/x 0xbefffcb0
0xbefffcb0: 0x00000001
(gdb) ni
0x00008068 in main ()
(gdb) x/4x 0xbefffcb0
0xbefffcb0: 0x00000001 0xbefffdc9 0x00000000 0xbefffddb
(gdb) x/4x 0xbefffca4
0xbefffca4: 0x0000000a 0x00000014 0x0000001e 0x00000001
(gdb) ni
0x0000806c in main ()
(gdb) ni
0x00008070 in main ()
(gdb) ni
0x00008074 in main ()
(gdb) disas main
Dump of assembler code for function main:
0x00008054 <+0>: mov r1, #10
0x00008058 <+4>: mov r2, #20
0x0000805c <+8>: mov r3, #30
0x00008060 <+12>: mov r4, sp
0x00008064 <+16>: push {r1, r2, r3}
0x00008068 <+20>: eor r1, r1, r1
0x0000806c <+24>: eor r2, r2, r2
0x00008070 <+28>: eor r3, r3, r3
=> 0x00008074 <+32>: ldmdb r4, {r1, r2, r3}
End of assembler dump.
(gdb) info reg
r0 0x0 0
r1 0x0 0
r2 0x0 0
r3 0x0 0
r4 0xbefffcb0 3204447408
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffca4 0xbefffca4
lr 0x0 0
pc 0x8074 0x8074 <main+32>
cpsr 0x10 16
(gdb) ni
Cannot access memory at address 0x0
0x00008078 in ?? ()
(gdb) info reg
r0 0x0 0
r1 0xa 10
r2 0x14 20
r3 0x1e 30
r4 0xbefffcb0 3204447408
r5 0x0 0
r6 0x0 0
r7 0x0 0
r8 0x0 0
r9 0x0 0
r10 0x0 0
r11 0x0 0
r12 0x0 0
sp 0xbefffca4 0xbefffca4
lr 0x0 0
pc 0x8078 0x8078
cpsr 0x10 16