2012-04-27 40 views
21

Tôi hiện đang viết một trình biên dịch C đơn giản, lấy một tệp .c làm đầu vào và tạo mã lắp ráp (cú pháp X86, AT & T). Everyting là tốt, nhưng khi tôi cố gắng thực hiện một hướng dẫn IDIVQ, tôi nhận được một ngoại lệ dấu chấm động. Dưới đây là đầu vào của tôi:Lắp ráp X86 - Xử lý lệnh IDIV

int mymain(int x){ 
    int d; 
    int e; 
    d = 3; 
    e = 6/d; 
    return e; 
} 

Và đây là mã được tạo của tôi:

mymain: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    movq %rsp, %rbp 
    .cfi_offset 6, -16 
    .cfi_def_cfa_register 6 
    movq %rdi, -40(%rbp) 
    movq $3, -8(%rbp) 
    movq $6, %rax 
    movq -8(%rbp), %rdx 
    movq %rdx, %rbx 
    idivq %rbx 
    movq %rax, -16(%rbp) 
    movq -16(%rbp), %rax 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size mymain, .-mymain 

Theo http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq% RBX nên sản xuất 6/d (quotient) trong % rax. Nhưng tôi nhận được một ngoại lệ dấu phẩy động, và tôi dường như không thể tìm ra vấn đề.

Mọi trợ giúp sẽ được đánh giá cao!

+0

Không liên quan đến câu hỏi này, nhưng bạn nên thực hiện 'movq% rdi, -40 (% rbp)' mà không điều chỉnh đăng ký 'esp'? Hoặc là OK vì vùng màu đỏ x64 '? –

Trả lời

23

phần đầu tiên của câu trả lời bí ẩn là chính xác, idiv thực hiện phân chia bit 128/64, vì vậy giá trị của rdx, giữ 64 bit trên từ cổ tức không được chứa giá trị ngẫu nhiên. Nhưng một phần mở rộng bằng không là cách sai để đi.

Như bạn có biến, bạn cần phải dấu mở rộng rax để rdx:rax. Có hướng dẫn cụ thể cho việc này, cqto (chuyển đổi quad thành oct) trong AT & T và cqo trong cú pháp của Intel. AFAIK phiên bản mới hơn của khí chấp nhận cả hai tên.

movq %rdx, %rbx 
cqto     # sign extend rax to rdx:rax 
idivq %rbx 
+0

+1 Hài hước cách tôi bỏ qua phần đã ký. – Mysticial

+0

Thật vậy, tôi đã chạy thử nghiệm của mình và gặp lỗi khi xử lý các giá trị đã ký. Tôi đã không nhìn thấy hướng dẫn này trước đây, nhưng có vẻ như để giải quyết vấn đề bây giờ. Cảm ơn bạn! –

+0

@Mysticial Xảy ra ngay cả khi tốt nhất :-) – hirschhornsalz

11

Hướng dẫn idivq chia số nguyên 128 bit (rdx:rax) bởi toán hạng.

  • rax giữ 64 bit thấp hơn của cổ tức.
  • rdx giữ 64 bit trên cổ tức.

Khi thương không phù hợp với 64 bit, nó sẽ ném ngoại lệ dấu phẩy động đó.

Vì vậy, những gì bạn cần làm là zero rdx:

movq %rdx, %rbx 
xorq %rdx, %rdx # zero "rdx" 
idivq %rbx 

Nếu bạn đang đối phó với số nguyên ký, bạn cũng cần phải đăng ký mở rộng rax để rdx:rax, có nghĩa là sao chép các bit rax dấu cho mỗi bit của rdx và được thực hiện với bí danh cqo cqto:

movq %rdx, %rbx 
cqo 
idivq %rbx 
+5

Zeroing rdx sẽ làm việc với các số dương, nhưng trong trường hợp của rax tiêu cực có lẽ rdx = -1 là cần thiết ... phải không? – marekb

+5

Tôi nghĩ rằng marekb là đúng - không nên 'xorq' instrcution là một lệnh' cqo' để ký mở rộng 'rax' vào' rdx: rax'? –

+0

Trong trường hợp này, với cách nhập có chữ ký: Tôi nghĩ vậy là có. –

Các vấn đề liên quan