2017-11-24 4 views
0

클래스 실험실에서이 작업을 수행하고 있으며 잘못된 곳으로 가고 있지 않습니다. 이 프로그램은 q 대신 l을 사용하여 모든 지시 사항에 접미사를 붙이면 작동합니다 (예 : rrmovq 대신 andq, rrmovl 대신 - andl). 나는 내가 잘못하고있는 것에 대해 약간의 포인터를 정말로 고맙게 생각한다.내가 잘못하고있는 부분을 이해하려고 노력 중 - 연결된 목록의 반복적 인 요약 Y86

.pos 0 
    init: irmovq Stack, %rsp  # Set up stack pointer 
    rrmovq %rsp,%rbp  # Set up base pointer 
    irmovq ele1,%rax 
    pushq %rax 
    call sum_list  # Execute main program 
    halt     # Terminate program 


    # Sample linked list 
    .align 8 
    ele1: .quad 0x00a 
    .quad ele2 
    ele2: .quad 0x0b0 
    .quad ele3 
    ele3: .quad 0xc00 
    .quad 0 

    # int sum_list(list_ptr ls) 
    sum_list: pushq %rbp 
     rrmovq %rsp,%rbp 
     xorq %rax,%rax  # val = 0 
     mrmovq 8(%rbp),%rdx # edx = ls 
     andq %rdx,%rdx  # Set condition codes 
     je  End 
    Loop:  mrmovq (%rdx),%rcx  # ecx = ls->val 
     addq %rcx,%rax  # val += ls->val 
     mrmovq 4(%rdx),%rdx # ls = ls->next ------ tried +8 insetead of 4 also 
     andq %rdx,%rdx  # Set condition codes 
     jne  Loop 
    End:  rrmovq %rbp,%rsp 
     popq %rbp 
     nop      # makes sure stop in 31 steps 
     ret 

# The stack starts here and grows to lower addresses 
    .pos 0x100 

스택 :

+0

q는 64 비트 피연산자 크기이고, l은 32 비트 피연산자 크기입니다. 목록 노드는 (포인터와 값) 두 개의 qword 멤버를 가지므로'q'가 정확해야합니다. '4 (% rdx)'는 틀린 것 같습니다 : 여러분은 값의 중간에서 4 바이트를 읽었습니까? (또는'q' 피연산자 크기의 8 바이트). 포인터와 정수가 모두 작기 때문에'l' 피연산자 크기가 작동해야합니다 (여전히 8의 오프셋을 사용하는 한). 따라서 32 비트로 자르면 값이 변경되지 않습니다. –

+0

코드를 싱글 스텝 처리 할 수있는'y86' 디버거가 있습니까? 레지스터를 사용하여 값을 봅니다. –

+0

나는 https://xsznix.github.io/js-y86/을 시도했는데 내 접미사가 l인데 내 접미사가 아닐 때는 내 코드가 작동한다. 한 가지 문제는 내가 렉스에 첫 번째 요소를 넣은 후 멈 추면 0xa 대신 0x0a00000000000000이 발생한다는 것입니다 (자체 좌회전이 가능할 수도 있음) –

답변

1

내가 잘못 함수의 인수를 받고 있다고 생각 : mrmovq 8(%rbp),%rdx%rdx로 함수의 반환 주소를 넣습니다.

ele1보다 약간의 바이트가 발생하기 때문에 충돌이 발생하지 않고 "이동 된"값을 생성하는 오프셋로드가 설명됩니다. IDK는 그 직후에 어떻게 추락하지 않습니다.


포인터 인수는 push %rax 인 호출자에 의해 스택에 배치됩니다. 그 후에 call은 리턴 주소 (8 바이트)를 푸시합니다.

push %rbp%rbp으로 복사하기 전에 %rsp을 다른 8 바이트 씩 감소시킵니다. 따라서 호출자가 푸시 한 포인터 arg는 16(%rsp)이며 16(%rbp)입니다.

mrmovq 16(%rbp),%rdx # rdx = ls 

디버깅 할 때 항상 가정을 테스트 해보십시오. 어려운 부분은 때로는 을 생각하고 있습니다. 당신이 생각하는 것입니다. 왜냐하면 종종 당신이 물기가있는 가능한 문제로 생각조차하지 않았기 때문입니다. (예를 들어, 함수 인자들을 얻고,이 경우.)


64 비트 86 코드가하는 것처럼, 레지스터 기능 인자들을 전달하기 쉬울 것이다. 예 : 첫 번째 인수는 %rdi이고, 두 번째 인자는 %rsi이며, x86-64 System V 호출 규칙이 사용합니다. 그러나 32 비트 x86 호출 규칙처럼 스택에 arg를 전달해야한다면 각 push은 8 바이트입니다.

OTOH, 스택을 사용하는 방법을 알고, 통화/푸시/팝이 무엇을하는지 추적하는 것이 중요합니다.

+0

@BonnyMahajan : 솔루션을 맹목적으로 사용하는 것보다 추론을 묻는 것이 좋습니다.arg에 스택을 넣는 호출자의'push % rax' 이후에'% rsp'에 대한 수정을 세었습니다 :'call'과'push % rbp'는 모두 8 바이트 값을 스택에 넣었습니다. 'mrmovq 16 (% rbp), % rdx' 코드 블록 바로 앞에있는 내 대답의 단락을 참조하십시오. 이해하기가 어렵습니까? 더 잘 표현하면 다른 초보자에게 더 쉽게 이해할 수 있을까요? –

+0

알았습니다. 감사 :) –

관련 문제