Tất cả các câu trả lời là tuyệt vời. Nhưng trên hết, tôi muốn chia sẻ một ví dụ.
Dưới đây là một chương trình cpp nhỏ:
#include <iostream>
int x;
int main(){
char buf[50];
x = 8;
if(x == 8)
printf("x is 8\n");
else
sprintf(buf, "x is not 8\n");
x=1000;
while(x > 5)
x--;
return 0;
}
Bây giờ, hãy tạo tập hợp mã ở trên (và tôi sẽ chỉ dán các phần của tập hợp có liên quan ở đây):
Lệnh tạo lắp ráp:
g++ -S -O3 -c -fverbose-asm -Wa,-adhln assembly.cpp
Và lắp ráp:
main:
.LFB1594:
subq $40, %rsp #,
.seh_stackalloc 40
.seh_endprologue
# assembly.cpp:5: int main(){
call __main #
# assembly.cpp:10: printf("x is 8\n");
leaq .LC0(%rip), %rcx #,
# assembly.cpp:7: x = 8;
movl $8, x(%rip) #, x
# assembly.cpp:10: printf("x is 8\n");
call _ZL6printfPKcz.constprop.0 #
# assembly.cpp:18: }
xorl %eax, %eax #
movl $5, x(%rip) #, x
addq $40, %rsp #,
ret
.seh_endproc
.p2align 4,,15
.def _GLOBAL__sub_I_x; .scl 3; .type 32; .endef
.seh_proc _GLOBAL__sub_I_x
Bạn có thể thấy trong hội đồng mà mã lắp ráp không được tạo sprintf
vì trình biên dịch giả định rằng nó x
sẽ không thay đổi bên ngoài chương trình. Và tương tự là trường hợp với while
vòng lặp. while
vòng lặp đã bị loại bỏ hoàn toàn do tối ưu hóa vì trình biên dịch đã xem nó như một mã vô dụng và do đó được gán trực tiếp 5
cho x
(xem movl $5, x(%rip)
).
Vấn đề xảy ra khi điều gì xảy ra nếu một quy trình / phần cứng bên ngoài sẽ thay đổi giá trị của x
một nơi nào đó giữa x = 8;
và if(x == 8)
. Chúng tôi hy vọng else
khối sẽ hoạt động nhưng không may là trình biên dịch đã cắt bỏ phần đó.
Bây giờ, để giải quyết việc này, trong assembly.cpp
, chúng ta hãy thay đổi int x;
để volatile int x;
và nhanh chóng xem mã lắp ráp tạo ra:
main:
.LFB1594:
subq $104, %rsp #,
.seh_stackalloc 104
.seh_endprologue
# assembly.cpp:5: int main(){
call __main #
# assembly.cpp:7: x = 8;
movl $8, x(%rip) #, x
# assembly.cpp:9: if(x == 8)
movl x(%rip), %eax # x, x.1_1
# assembly.cpp:9: if(x == 8)
cmpl $8, %eax #, x.1_1
je .L11 #,
# assembly.cpp:12: sprintf(buf, "x is not 8\n");
leaq 32(%rsp), %rcx #, tmp93
leaq .LC0(%rip), %rdx #,
call _ZL7sprintfPcPKcz.constprop.0 #
.L7:
# assembly.cpp:14: x=1000;
movl $1000, x(%rip) #, x
# assembly.cpp:15: while(x > 5)
movl x(%rip), %eax # x, x.3_15
cmpl $5, %eax #, x.3_15
jle .L8 #,
.p2align 4,,10
.L9:
# assembly.cpp:16: x--;
movl x(%rip), %eax # x, x.4_3
subl $1, %eax #, _4
movl %eax, x(%rip) # _4, x
# assembly.cpp:15: while(x > 5)
movl x(%rip), %eax # x, x.3_2
cmpl $5, %eax #, x.3_2
jg .L9 #,
.L8:
# assembly.cpp:18: }
xorl %eax, %eax #
addq $104, %rsp #,
ret
.L11:
# assembly.cpp:10: printf("x is 8\n");
leaq .LC1(%rip), %rcx #,
call _ZL6printfPKcz.constprop.1 #
jmp .L7 #
.seh_endproc
.p2align 4,,15
.def _GLOBAL__sub_I_x; .scl 3; .type 32; .endef
.seh_proc _GLOBAL__sub_I_x
Ở đây bạn có thể thấy rằng các mã lắp ráp cho sprintf
, printf
và while
vòng lặp đã được tạo ra. Ưu điểm là nếu x
biến được thay đổi bởi một số chương trình hoặc phần cứng bên ngoài, sprintf
một phần của mã sẽ được thực thi. Và while
vòng lặp tương tự có thể được sử dụng cho chờ đợi bận rộn bây giờ.