2016-01-25 14 views
5

Tôi mới tham gia hội thảo trong C và tôi không biết cách khắc phục lỗi này. Tôi đang tạo một hàm có nghĩa là viết một tệp. Những gì tôi có là:Tại sao asm có những ràng buộc không thể khi tôi đặt tên cho sổ đăng ký?

ssize_t mywrite(int fd, const void *buf, size_t count) { 
// return write(fd, buf, count); 
    ssize_t var; 
    __asm__("movl $4,%%eax\n\t" // Write 
     "movl %1,%%ebx\n\t" 
     "movl %2,%%ecx\n\t" 
     "movl %3,%%edx\n\t" 
     "int $0x80\n\t"   // System call 
     "movl %%eax,%0" 
     :"=r"(var) 
     :"r"(fd),"r"(buf),"r"(count) 
     :"%eax","%ebx","%ecx","%edx" 
    ); 
    return var; 
} 

Asm của tôi có nghĩa vụ phải làm tương tự như viết (fd, buf, count); Khi tôi biên dịch nó, tôi nhận được toán hạng "asm" có những ràng buộc không thể ". Tuy nhiên, nếu không đặt tên các biến và nhận các giá trị trực tiếp từ ngăn xếp, tôi sẽ không nhận được lỗi. Đây là mã số

__asm__("movl $4,%%eax\n\t" 
     "movl 8(%%ebp),%%ebx\n\t" 
     "movl 12(%%ebp),%%ecx\n\t" 
     "movl 16(%%ebp),%%edx\n\t" 
     "int $0x80\n\t" 
     "movl %%eax,%0" 
     :"=r"(var) 
     : 
     :"%eax","%ebx","%ecx","%edx" 
    ); 

Tôi có thể sử dụng mã thứ hai, tuy nhiên, tôi cần nó được biên dịch với tối ưu hóa 2. Sau đó,% ebp sẽ không trỏ đến nơi tôi cần. Tôi đã thử sử dụng "a", "b", "c" và "d" thay vì "r", nhưng không thành công. Bất cứ ai cũng có thể giúp đỡ? Cảm ơn: D

+0

Bạn có đang biên dịch ở chế độ 64 bit không? – fuz

Trả lời

7

Vấn đề là ràng buộc r có nghĩa là đăng ký, nhưng CPU của bạn chỉ đơn giản là không có quá nhiều đăng ký!

Bạn có thể sử dụng các hạn chế bộ nhớ m:

:"m"(fd),"m"(buf),"m"(count) 

Điều đó sẽ tạo ra hướng dẫn như:

movl 8(%ebp),%ebx 

Nhưng tôi sẽ khuyên bạn nên sử dụng x86 constraints trong tất cả vinh quang của nó:

ssize_t mywrite(int fd, const void *buf, size_t count) { 
    ssize_t var; 
    __asm__(
     "int $0x80" 
     :"=a"(var) 
     :"0"(4), "b"(fd),"c"(buf),"d"(count) 
    ); 
    return var; 
} 

Điều đó, với -Ofast cho:

push %ebx 
mov $0x4,%eax 
mov 0x10(%esp),%edx 
mov 0xc(%esp),%ecx 
mov 0x8(%esp),%ebx 
int $0x80 
pop %ebx 
ret 

Và với -Os:

push %ebp 
mov $0x4,%eax 
mov %esp,%ebp 
push %ebx 
mov 0x10(%ebp),%edx 
mov 0x8(%ebp),%ebx 
mov 0xc(%ebp),%ecx 
int $0x80 
pop %ebx 
pop %ebp 
ret  

Lưu ý như thế nào, nhờ vào việc sử dụng các ràng buộc thay vì đăng ký theo tên, trình biên dịch có khả năng tối ưu hóa mã hơn nữa.

+0

Tôi đã thử các ràng buộc x86 và nó đang hoạt động ngay bây giờ! Cảm ơn nhiều! Điều tuyệt vời để biết cách thay thế này: D – Behnken

+1

@Behnken: lưu ý rằng cách tải trực tiếp-từ-chồng (cách thứ 2 trong câu hỏi của bạn) sẽ phá vỡ ngay khi chức năng của bạn được gạch chân. Vì vậy, cách đó thậm chí không phải là một thay thế, nó chỉ bị hỏng. (oh tôi nghĩ bạn biết điều đó, dựa trên văn bản). Cách đầu tiên trong câu hỏi của bạn sẽ tạo mã đã tải dữ liệu vào các thanh ghi khác, sau đó chạy các lệnh di chuyển reg-reg của bạn, vì vậy sẽ mất gấp đôi số lượng hướng dẫn nếu cần. Như thường lệ, hãy viết càng ít hướng dẫn càng tốt, hãy để nó lên trình biên dịch để chọn cách lấy dữ liệu vào/ra khỏi nội tuyến của bạn. –

+0

@PeterCordes Oh, đó là sự thật ... Tôi đã không nhận ra rằng cách đó đã thực sự bị phá vỡ ngay từ cái nhìn đầu tiên. Cảm ơn: D Điều thú vị cần lưu ý là mã được tối ưu hóa tốt hơn theo cách này. Như tôi đã nói, tôi rất mới với asm, bắt đầu học, tbh. Đây là một lời khuyên tôi sẽ mang theo bên mình. Cảm ơn vì đã cho nó! – Behnken

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