2012-11-27 4 views
0

어셈블리에서 다음 작업에 문제가 있습니다. 어셈블리 IA32에서 작업 중입니다. -4 (% ebp) = x 및 -8 (% ebp) = y라고 가정하고 이미 사용자로부터 가져온 것입니다 (둘 다 32 비트 길이). 이 코드입니다 : 나는이 개 긴 숫자를 곱하고 64 바이트에 도달 할 경우에도 결과를 인쇄 할 수 있기를 원하기 때문에 곱셈의 결과가 %의 LLU에어셈블리 곱하기 작업 64 비트

format1: .string "Multiply : %u * %u = %llu\n" 
format2: .string "Divide : %u/%u = %u\n" 

# operation multiply 
movl -4(%ebp), %eax 
mull -8(%ebp) 
pushl %edx 
pushl %eax 
pushl -8(%ebp) 
pushl -4(%ebp) 
pushl $format1 
call printf 

# operation divide 
movl -4(%ebp), %eax 
divl -8(%ebp) 
pushl %eax 
pushl -8(%ebp) 
pushl -4(%ebp) 
pushl $format2 
    call printf 

이유입니다. 또한 % edx에서 mull 명령은 64 바이트 결과의 "다른 32 바이트"를 저장하므로 printf에도 스택으로 푸시해야합니다. 예 :

Multiply : 4000000000 * 2 = 16000000000 

은 또한, I는 X.YZ 결과를 반환하기 위해 4 분할기 (3)의 조작을 할 :이 결과를 원한다. (가수가 2 개 이상이고 반올림하지 않음) 예 : 19 1000

Divide : 3/4 = 0.75 

:

Divide : 19/1000 = 0.01 

8과 2

: 정말 결과하지만 성공을 얻기 위해 많이 노력

Divide : 8/2 = 4.00 

. 감사합니다. :)

+2

'4000000000 * 2 = 16000000000'? 스타 워즈 : 펜티엄이 역습? –

+0

예를 들면, 최대 64 비트의 결과를 얻을 수 있어야합니다. 그리고이 예제가 내 코드에서 아직 작동하지 않습니다./ – Jjang

+1

왜? 왜이 C 또는 C++ 태그를 사용 했습니까? C를 고집한다면 C 전문가, 즉 C 컴파일러에게 어떻게 그런 일을 할 것인지 물어 보았습니까? (예 : gcc 또는 clang을 사용하면 -S가 꽤 좋은 어셈블리 코드를 생성합니다.) –

답변

0

mull은 정수 곱셈이고 divl은 정수 나누기입니다. 부동 소수점 숫자의 경우 부동 소수점 명령어 fmul 및 을 사용할 수 있습니다.

제리 코핀 (Jerry Coffin)이 그의 의견에서 제시 한 바와 같이, 정수 곱셈 이전의 인수를 각각 예를 들어 스케일합니다. 결과 정수 값을 100 * 100 = 10000 배로 너무 크게 처리하십시오.

0

곱셈 should work as-is. 부동 소수점 결과를 얻기 위해 나눗셈을 수행하는 방법은 이미 answered in your other question입니다. 두 자릿수로만 인쇄 할 필요가있는 경우 적절한 형식 문자열을 사용할 수 있습니다.

업데이트 : 두 자리로 절단을 보여주는 코드를 작업 :

.comm x,4,4 
.comm y,4,4 

.section .rodata 

format1: .string "Div : %d/%d = %.2f\n" 
format2: .string "Mod : %d %% %d = %d\n" 
format3: .string "Multiply : %u * %u = %llu\n" 
format4: .string "%d %d" 
const100: .int 100 

.text 
.globl main 
.type main, @function 
main: 
    subl $32, %esp # allocate space, preserve alignment 

    movl $format4, (%esp) 
    movl $x, 4(%esp) 
    movl $y, 8(%esp) 
    call scanf 

# operation divide 
    fildl x 
    fimul const100 
    fidivl y 
# truncate to integer 
# use this if current FPU rounding mode 
# is known to be truncate 
# frndint 
# otherwise use this 
    fnclex 
    fnstcw (%esp)  # save a copy to modify 
    fnstcw 2(%esp)  # and a copy to preserve 
    orw $0x0c00, (%esp) # rounding mode = truncate 
    fldcw (%esp)  # activate 
    frndint    # do the truncate 
    fldcw 2(%esp)  # restore original 
# end of truncate code 
    fidiv const100 
    fstpl 12(%esp) # x/y 

    movl $format1, (%esp) 
    movl x, %eax 
    movl %eax, 4(%esp) 
    movl y, %eax 
    movl %eax, 8(%esp) 
    call printf 

# operation modulo 
    movl x, %eax 
    cltd 
    idivl y 
    movl $format2, (%esp) 
    movl x, %eax 
    movl %eax, 4(%esp) 
    movl y, %eax 
    movl %eax, 8(%esp) 
    movl %edx, 12(%esp) 
    call printf 

# operation multiply 
    movl x, %eax 
    mull y 
    movl $format3, (%esp) 
    movl x, %ecx 
    movl %ecx, 4(%esp) 
    movl y, %ecx 
    movl %ecx, 8(%esp) 
    movl %eax, 12(%esp) 
    movl %edx, 16(%esp) 
    call printf 

    addl $32, %esp 
    xor %eax, %eax 
    ret 

See in operation.

가 일부 유용한 실시 예 여기

here 찾을 수

+0

글쎄, 멀 doesntnt 작동 : S 및 분할에 대해, 나는 당신의 대답을 이해하지만 2 자리 만 필요합니다. 어떤 적절한 형식으로 이야기하고 있습니까? – Jjang

+0

[작동중인 곱셈 코드] (http://ideone.com/nBcKkI)를 참조하십시오. 형식 문자열에 대해서는'% .2f'를 사용해 두 자리로 인쇄하십시오. – Jester

+0

플로트가 결과를 반올림하고, 19와 1000을 시도합니다. 0.1 대신 0.2를줍니다. – Jjang

0

32 비트 수와 출력 64 비트 결과를 승산하는 방법의 예이다 리눅스 GCC] 부문

#include <stdio.h> 

char *fr = "MUL %u * %u = %llu\n"; 

int main() 
{ 
     __asm__ (
         "subl $0x14, %esp\n\t" 
         "movl $10, %eax\n\t" 
         "movl %eax, 0x4(%esp)\n\t" 
         "movl $100, %ebx\n\t" 
         // Multimpy two 32bit values and save 64bit result in edx:eax 
         "mull %ebx\n\t" 

         // Call printf 
         "movl fr, %esi\n\t" 
         "movl %esi, (%esp)\n\t" 
         "movl %ebx, 0x8(%esp)\n\t" 
         "movl %eax, 0xC(%esp)\n\t" 
         "movl %edx, 0x10(%esp)\n\t" 
         "call printf\n\t" 
         "addl $0x14, %esp\n\t"); 

     return 0; 
} 

gcc -m32 ./ttt.c; ./a.out 
MUL 10 * 100 = 1000 

데이터를 부동 소수점 값으로 변환하고 fdiv 명령어를 사용해야합니다.

추신. push%esp으로 변경되므로 pop을 복원 스택 포인터와 동일한 횟수만큼 수행해야합니다. 그렇지 않으면 정의되지 않은 동작이 발생합니다.

관련 문제