2011-03-04 2 views
10

저는 어셈블리 프로그래밍에 익숙하지 않습니다. 저는 GCC (Linux)에서 x86 플랫폼을 사용하고 있습니다.어셈블리 함수에 대한 포인터 전달

이 나는대로 C에서 호출하고자하는 기능을 가지고 :

myfunc (unsigned char * s1, unsigned char * s2, int someint); 

일부 처리를하고, 등, 증가와 비교 후, S1과 S2의 메모리 위치를 가지고 그들을 비교합니다 기능 그것은 간다. 이것은 memcmp와 비슷하지만 더 많이하고 있습니다.

내 질문 : 포인터를 어셈블리 함수에 전달하면 어떻게됩니까? 그런 다음 "이 메모리 주소에 저장된 값을 알려주십시오"라고 어떻게 말합니까? 여기

는 지금까지이 작업은 다음과 같습니다

가 스택에서 첫 번째 함수의 인수 ("S1")을 얻으려면, 내가 someaddress 32 비트 정수 (이렇게, 나는 32에서 일하고 있어요 비트 프로세서) I 등 %eax (또는 %ebxsomevar 넣으면

movl 8(%esp), %ecx 
movl %ecx, someaddress 

) 다음은의 printf를 %p와, I는 주소 및 서명 숯불 포인터의 주소가 "s1"나는 전달 볼 그것은 동일합니다. 하지만 실제로 내가 한 일은 메모리 주소를 가져 와서 정수로 변환 한 다음 그 정수를 someaddress에 넣는 것입니다. 예를 들어

, 그때이 작업을 수행 할 경우 :

movl pos1, %eax 
movl pos2, %ebx 
cmp (%eax),(%ebx) 

내가 얻을 "오류 : 'CMP'에 대한 너무 많은 메모리 참조를".

그래서 ...

  • 방법에 대한 포인터를 전달하고 포인터로 유지하기 위해 ;-) "당신이 망쳐"를 제외하고 나는 그게 무슨 뜻인지 전혀 확실하지 않다?
  • 어셈블리에서 상기 포인터의 값을 사용하는 방법은 무엇입니까? (예 : C에서 *ptr과 같은)

LEA 피연산자를보고 싶습니까?

저는 Richard Blum의 "Professional Assembly Programming"을 가이드로 사용하고 있지만 Blum은이 사례를 다루지 않습니다.

업데이트

은 배운 응답을 주셔서 대단히 감사합니다!

불행히도, 나는 아직도 참조 할 수 없습니다.

다음은 단순화 된 예입니다. 어셈블리 함수는 포인터를 가져 와서 다시 에코해야합니다.대신 내가 얻을 :

first_ptr points to 81 (should be 81) <-- from C program 
the value is -1543299247 <-- printf called from within assembler 
the value is -6028513 <-- printf called from within assembler 
my function returned -6028513 <-- return value printed from C program 

C 프로그램 :

#include <stdio.h> 
#include <string.h> 

int main (void) { 
     unsigned char first; 
     unsigned char * first_ptr; 

     first = 'Q'; 
     first_ptr = &first; 

     printf ("first_ptr points to %i (should be 81)\n",*first_ptr); 

     printf ("my function returned %i\n", myfunc(first_ptr)); 
     return 0; 
} 

총회 프로그램 : cmp에 피연산자의

.section .data 

msg: 
    .asciz "the value is %i\n" 

.section .bss 
.lcomm str, 8 

.section .text 
.type myfunc, @function 
.globl myfunc 
myfunc: 

    # save stack 
    pushl %ebp 
    movl %esp, %ebp 

    # save string arg from stack to "str" 
    movl 8(%esp), %ecx 
    movl %ecx, str 

    # let's try printing the ecx dereference 

    pushl (%ecx) 
    pushl $msg 
    call printf 

    # put the value of str on the stack 
    # and call printf 

    pushl (str) 
    pushl $msg 
    call printf 

    # now return the character at pos1 
    movl (str), %eax 

    # restore the stack 
    movl %ebp, %esp 
    popl %ebp 

    ret 
+0

업데이트 된 코드 문제 : 값을 인쇄하려면 변수가 단지 8 비트 인 반면 32 비트를 푸시해야합니다. 32 비트 (C가하는 것)로 확장하거나 형식 문자열을 변경할 수 있습니다. -1543299247의 하위 8 비트는 실제로 예상대로 81로 평가됩니다. 두 번째 인쇄 및 반환 : 쓰기 (str)로 이중 참조를 사용하려고 시도 했으므로 x86에는 그런 것이 없습니다. 당신이 나에게 묻는다면 어셈블러는 에러를 던져야하지만 대신에 괄호를 조용히 버린다. – Jester

답변

8

하나 이상의 레지스터 수 있습니다. 두 메모리 위치의 내용을 비교하려는 경우 레지스터 중 하나를 넣어야합니다. 당신이 물어 보는 레지스터에 그것을 가져 오는 방법? 이제 예제 코드로 이미 완료했습니다. 이 줄은

movl 8(%esp), %ecx 

% esp + 8에서 4 바이트를 가져 와서 % ecx에 넣습니다. C와 같은 psuedocode :

ecx = *(esp + 8); 

잘하면 그게 의미가 있습니다. 유사한 작업을 수행하여 포인터를 스택 및 레지스터로 가져온 다음 역 참조를 수행하고 역 참조 된 값을 비교하는 등의 작업을 수행 할 수 있습니다. 더 궁금한 점이 있으면 알려주세요.

편집 - 당신의 세분화 질문 : 당신은 이미 그 일을하고

  1. 하고 movl 8(%esp), %ecx 명령, 또는 뭔가 당신이 필요한 모든 것을 할 것 같은.

    movb (%ecx), %edx 
    

    를 유사한 C 형태의 가상 년 : 포인터에서 첫 번째 바이트를로드 할 %ecx에 명령에서 위 - 예를 들어,

  2. how to use the value of said pointer in assembly? (e.g., like *ptr in C)

    당신은 다시 ()를 사용할 필요가 내가 위에서 그것을 사용하는 방법,이 명령은 다음과 같습니다

    edx = *(unsigned char *)ecx; 
    
  3. Do I want to look at the LEA operand?

    아마 당신이 제공 한 문제에 대한 설명에 기반하지 않을 것입니다. 그것은 항상 가능합니다. lea은 C에서 & 연산자처럼 작동합니다.예를 들어,이 명령 : 단순히

    edx = &(*(ecx + 12)) 
    

    이상 :이 예는 조금 바보입니다

    edx = ecx + 12 
    

    , 우리가 '이후

    lea 12(%ecx), %edx 
    

    은 우리의 의사 코드로 변환 할 수 있습니다 상대적으로 복잡하지 않은 주소 지정 모드를 사용하지만 다음과 같은 경우는 어떻습니까?

    lea 1(%edx,%ecx,4), %eax 
    

    의미 :

    eax = &(edx[ecx * 4] + 1) 
    

종종 문제가 이러한 종류의 가장 쉬운 해결책은, C에서 루틴을 쓰기 컴파일하고 결과를 분해하는 것입니다.

편집 2 :

귀하의 예제 프로그램은 거의 바로 보인다,하지만 당신은 메모리에 역 참조 포인터에 노력하고 - 첫번째 레지스터에 그 포인터를 얻을하고 확인해야합니다.

관련 문제