2016-12-07 2 views
0

나는 프로그램 명령 행 인자로 놀고있다. 특히 문자열 argv [1]에 대한 몇 가지 테스트를 시도하고 있습니다. argv [1]에 주소를 가져 오는 두 단계의 방법을 사용하면 코드가 올바르게 실행됩니다.NASM 메모리 어드레싱

mov ebx, [ebp+12] 
mov eax, [ebx+4] ; address of argv[1] 

한 단계를 사용하면 내 프로그램이 지껄입니다.

mov eax, [ebp+16] ; address of argv[1] 

어느 방법이든지 [ebp + 16] 주소를 참조한다고 잘못 생각합니까? 나는 사소한 것을 놓치고 있는가?

+5

이들은 동일하지 않습니다. 첫 번째는'* (* (ebp + 12) +4)'를 두 번째는'* (ebp + 16)'만합니다. 역 참조 해제는 생략 할 수 없습니다. – Jester

+2

덕분에 @ DanMašek는 우스꽝스럽게 도움이되지 못했다. – Eric

+0

@Jester 많은 것을 감사드립니다. 나는 그것에 대해 생각할 것이다. – Eric

답변

4

어셈블리에서 포인터에 대한 포인터로 작업 할 때 혼동되기 쉽습니다. 인수로 전달하면

argv 진리 argv 년에는 char 또는 char** argv 포인터에 대한 포인터이며, 자신의 항목 유형에 대한 포인터로 C 배열의 부패 이후에 "문자열의 배열"또는 더 나은는 char에 대한 포인터의 배열입니다 .

이것은 문자열의 문자에 액세스하기 위해 두 개의 역 참조가 필요하고 이러한 문자열에 대한 포인터에 액세스하기 위해 하나의 문자열을 액세스해야한다고 알려줍니다.

파라미터 역순 스택에 전달되는 cdecl을 규칙을 가정하면, 우리는 argc의 값 ebp+0ch에 있음이 표준 프레임 포인터를 설정하는 기준 프롤로그 가정.
ebp은 포인터의 의미를 가지고 있으므로 ebp+0chargc 값으로 다른 포인터를 얻기위한 포인터 산술 일뿐입니다.

ebp+0ch에 C 유형을 기꺼이 쓸 경우 char***이 될 것이므로 포인터 argv[1]에 액세스하려면 2 개의 역 참조가 필요합니다.

코드 ESIargv[1]이 얻을 :

;typeof(ebp+0ch) = char*** 

mov esi, DWORD [ebp+0ch]  ;1st defer, esi = argv, typeof(esi) = char** 
mov esi, DWORD [esi+04h]  ;2nd defer, esi = argv[1], typeof(esi) = char* 

;Optional, Get a char 
mov al, BYTE [esi]   ;3rd defer, al = argv[1][0], typeof(al) = char 

유형 확인.


소리가 혼란 스럽습니까?
그 포인터를 그려 보겠습니다!

 The stack          The memory 

100ch | 2000h | argv       2000h | 2008h | argv[0] 
1008h | 2  | argc       2004h | 2010h | argv[1] 
1004h | yyyyyy | return address    2008h | file | argv[0][0..3] 
1000h | xxxxxx | old frame pointer   200ch | .a\0\0 | argv[0][4..7] 
               2010h | -arg | argv[1][0..3] 
EBP = 1000h         2014h | 1\0\0\0 | argv[1][4..7] 

ebp+0ch는 1000H + = 0CH 100ch이고 그것은 argv 값의 주소이다.
mov esi, DWORD [ebp+0ch]mov esi, DWORD [100ch]과 같으며 ESI을 2000h로 설정합니다.
2000h는 배열 인 argv의 값이므로 argv[0]의 주소입니다.

argv[1]의 주소는 4 바이트 앞에 있으므로 2000h + 04h = 2004h입니다.
mov esi, DWORD [esi+04h]mov esi, DWORD [2004h]과 같으며 2010h에 ESI을 설정합니다.
2010h는 "-arg1"문자열의 주소입니다. 사진 위의 C 나 C++ argv[argc] 등의 준수 표준 0
해야 아니라고


주 나는 왼쪽 그 사진 중.

+0

잘 생각하고 정교한 답변 주셔서 감사합니다. 나는 C에서 포인터의 관점에서 이해할 수 있습니다. 주소에 대한 표기법을 신속하게 자세히 설명 할 수 있습니까? 나는 h와 ch에 혼란스러워. – Eric

+4

@Eric :'h' 접미사는 16 진수를 의미하며 DOS/Windows 어셈블리에서는 '0x100c'대신 사용할 수 있습니다. 'c'는 16 진수입니다. (많은 DOS/Windows 어셈블러는'0xDEADBEEF'를 지원하지 않고, 읽기 쉽지 않은 -IMO'0DEADBEEFh' 만 지원합니다. 불행하게도이 후행 스타일은 x86 asm에서 흔히 볼 수 있습니다.) NASM은 두 가지 방법과 다른 접미사/접두사를 지원합니다. 다른 수의 기초. (기본 2는 종종 유용합니다). –

-2

귀하의 질문에 대한 답변입니다.

mov eax, [ebp+16] 
mov ebx, ebp 
add ebx, 12 
mov eax, [ebx+4] 

mov eax, [ebp+16] 
lea ebx, [ebp+12] 
mov eax, [ebx+4] 

또는

코드의 몇 바이트를 저장하지만 그들은 기능적으로 동일합니다.

+2

mmm ... 왜'mov eax, [ebp + 16]'를 사용하지 않고'eax' 2/3 명령을 덮어 쓸 때 사용하는지는 명확하지 않습니다. 게다가, 당신의 코드는'argv [1]'이 아니라 * main *의 3 번째 (비표준이지만 종종 제공되는) 매개 변수에 접근하는'mov eax, [ebp + 16]'을 작성하는 어리석은 방법 일뿐입니다. 이것은 OP 질문에 대한 대답이 아닙니다. –

관련 문제