2016-09-23 5 views
0

다른 숫자 (var b) 번으로 숫자 (var a)를 추가하여 곱셈을 수행하는 for 루프를 작성하려고합니다.잘못된 높은 숫자를 반환하는 어셈블리 곱셈 루프

.globl times 

times: 
movl $0, %ecx  # i = 0 

cmpl %ecx, %esi  #if b-i 
jge end    # if >= 0, jump to end 


loop: 
addl (%edi, %eax), %eax #sum += a 
incl %ecx    # i++ 
cmpl %esi, %ecx   # compare (i-b) 
jl loop     # < 0? loop b times total 

end: 
ret 

나는 어디로 가고 있습니까? 나는 논리를 훑어 보았고 문제가 무엇인지 알 수 없다.

+0

코드를 제거하여 질문을 훼손하지 마십시오. 그 대답은 무의미합니다. 당신은 EBX를 사용하는 경우 –

답변

3

TL : DR : EAX가 0이 아니며 ADD 명령어가 메모리 피연산자를 사용하고 있습니다.


디버거를 사용해야합니다. EAX가 처음부터 0이 아니라는 것을 쉽게 알 수 있습니다. gdb를 사용하여 asm을 디버깅하는 방법에 대한 팁은 태그 위키를 참조하십시오.

args (a 및 b)가 % edi 및 % esi에 있으므로 x86-64 System V ABI를 사용하고있는 것 같습니다.

함수를 시작할 때 args를 보유하고있는 레지스터 이외의 레지스터는 가비지가 있다고 가정해야합니다. 인 레지스터의 높은 부분조차도 args를 가지고있는은 쓰레기를 담을 수 있습니다. (이 규칙에 대한 예외 : unofficially, narrow args are sign or zero extended to 32-bit by the caller)


어느 인수 포인터, 그래서 당신이 그들을 반 참조하지 않아야합니다. add (%edi, %eax), %eax은 32 비트 주소를 EDI + EAX로 계산 한 다음 거기에서 32 비트를로드합니다. EAX (대상 피연산자)에 해당 워드를 추가합니다.

정수 arg를 포인터로 사용하기 때문에 프로그램에서 segfault가 발생하지 않았다는 사실에 놀랐습니다.

ADD와 같은 많은 x86 명령어의 경우 대상 피연산자는 쓰기 전용이 아닙니다. add %edi, %eax은 입니다. 나는 당신이 add %src1, %src2, %dst과 같은 명령어를 가질 수있는 3 피연산자 RISC 구문과 혼재하고 있다고 생각합니다.

x86에는 과 같이 최근 확장으로 추가 된 지침이 있지만 일반적인 지침은 모두 파괴 대상이있는 2 피연산자입니다. (대신 주소에서로드, 그것은 대상에 주소를 저장하는 LEA을 제외하고. 그래서 lea (%edi, %eax), %eax 당신은 심지어 다른 레지스터에 결과를 넣을 수 있습니다. 작동합니다. LEA is great for saving MOV instructions by doing shift+add and a mov all in one instruction, using the addressing mode syntax and machine-code encoding.


을 당신은 코멘트를 가질 수 ie eax = sum + (a x 4bits)을 말한다. 어떤 단서가 당신이 거기에 대해 이야기하지하는지. A는 4 바이트 (안 비트)이며, 당신은 아무것도에 의해 (%의 EDI)을 곱하여 아닙니다.

그냥 재미를 위해, 여기 방법

나는 당신의 기능을 쓸 것입니다 (만약 내가 피해야 만한다면 imul %edi, %esi/mov %esi, %eax). 두 인수가 모두 음수가 아닌 것으로 가정하여 간단하게 유지합니다. args가 부호있는 정수이고 b이 음수이면 -b 번 반복해야하고, 약간의 추가 코드가 필요합니다.

# args: int a(%edi), int b(%esi) # comments are important for documenting inputs/outputs to blocks of code 
# return value: product in %eax 
# assumptions: b is non-negative. 
times: 

    xor %eax, %eax  # zero eax 

    test %esi, %esi  # set flags from b 
    jz loop_end   # early-out if it's zero 

loop:      # do{ 
    add %edi, %eax  # sum += a, 
    dec %esi    # b-- (setting flags based on the result, except for CF so don't use ja or jb after it) 
    jge loop    # }while(b>=0) 

loop_end: 
    ret 

들여 쓰기 스타일에주의하십시오. 따라서 분기 타겟을 쉽게 찾을 수 있습니다. 어떤 사람들은 루프 내부 지침을 추가로 들여 쓰기를 좋아합니다.

귀하의 방법은 (당신이 바로 그것을 할 경우) 잘 작동하지만 내 방식은 카운트 다운을하는 ASM에서 쉽게 (추가 레지스터가 필요하지 않으며, 상한을 잡고 즉시)임을 보여줍니다. 또한 중복을 피하는 것이 좋습니다. 하지만 적어도 작동 편안하게 코드를 작성하는 것 때까지 최적화에 대해 걱정하지 마십시오.

1

이것은 의사 코드이므로 염두에 두십시오.

mov X,ebx <- put into EBX your counter, your B 
mov Y,edx <- put into EDX your value, your A 
mov 0,eax <- Result 

loop: 
add eax,edx 
dec ebx 
jnz loop <- While EBX is not zero 

위의 구현은 EAX에 대한 가치를 창출해야합니다. 코드가 eax 초기화가 누락 된 것처럼 보입니다.

+0

, 당신은 저장/발신자의 가치를 복원해야합니다. 그래서 OP는 ECX를 사용했습니다. 하지만 당신은 EAX로 시작하는 쓰레기를 보유하고 있으며 그 영업의 코드에서 문제 중 하나를 잘한다는 것. –