我努力學習的x86-64內聯彙編,並決定實施這個非常簡單的交換方法簡單單a
和b
按升序排列:如何在GCC內聯裝配中使用標籤?
#include <stdio.h>
void swap(int* a, int* b)
{
asm(".intel_syntax noprefix");
asm("mov eax, DWORD PTR [rdi]");
asm("mov ebx, DWORD PTR [rsi]");
asm("cmp eax, ebx");
asm("jle .L1");
asm("mov DWORD PTR [rdi], ebx");
asm("mov DWORD PTR [rsi], eax");
asm(".L1:");
asm(".att_syntax noprefix");
}
int main()
{
int input[3];
scanf("%d%d%d", &input[0], &input[1], &input[2]);
swap(&input[0], &input[1]);
swap(&input[1], &input[2]);
swap(&input[0], &input[1]);
printf("%d %d %d\n", input[0], input[1], input[2]);
return 0;
}
上面的代碼按預期工作當我運行這個命令:
> gcc main.c
> ./a.out
> 3 2 1
> 1 2 3
但是,只要我把優化調度上出現以下錯誤信息:
> gcc -O2 main.c
> main.c: Assembler messages:
> main.c:12: Error: symbol `.L1' is already defined
> main.c:12: Error: symbol `.L1' is already defined
> main.c:12: Error: symbol `.L1' is already defined
如果我對它有正確的理解,這是因爲gcc
試圖在開啓優化時內聯我的swap
函數,導致在程序集文件中多次定義標籤.L1
。
我試圖找到這個問題的答案,但似乎沒有任何工作。在this previusly asked question它建議使用當地的標籤,而是和我已經試過了藏漢:
#include <stdio.h>
void swap(int* a, int* b)
{
asm(".intel_syntax noprefix");
asm("mov eax, DWORD PTR [rdi]");
asm("mov ebx, DWORD PTR [rsi]");
asm("cmp eax, ebx");
asm("jle 1f");
asm("mov DWORD PTR [rdi], ebx");
asm("mov DWORD PTR [rsi], eax");
asm("1:");
asm(".att_syntax noprefix");
}
但嘗試運行的程序現在我得到一個分段錯誤,而不是當:
> gcc -O2 main.c
> ./a.out
> 3 2 1
> Segmentation fault
我也嘗試過建議的解決方案,以this previusly asked question並更名.L1
到CustomLabel1
的情況下,將有一個名稱衝突,但它仍然給我的老錯誤:
> gcc -O2 main.c
> main.c: Assembler messages:
> main.c:12: Error: symbol `CustomLabel1' is already defined
> main.c:12: Error: symbol `CustomLabel1' is already defined
> main.c:12: Error: symbol `CustomLabel1' is already defined
最後我也試過this suggestion:
void swap(int* a, int* b)
{
asm(".intel_syntax noprefix");
asm("mov eax, DWORD PTR [rdi]");
asm("mov ebx, DWORD PTR [rsi]");
asm("cmp eax, ebx");
asm("jle label%=");
asm("mov DWORD PTR [rdi], ebx");
asm("mov DWORD PTR [rsi], eax");
asm("label%=:");
asm(".att_syntax noprefix");
}
但後來我得到這些錯誤,而不是:
main.c: Assembler messages:
main.c:9: Error: invalid character '=' in operand 1
main.c:12: Error: invalid character '%' in mnemonic
main.c:9: Error: invalid character '=' in operand 1
main.c:12: Error: invalid character '%' in mnemonic
main.c:9: Error: invalid character '=' in operand 1
main.c:12: Error: invalid character '%' in mnemonic
main.c:9: Error: invalid character '=' in operand 1
main.c:12: Error: invalid character '%' in mnemonic
所以,我的問題是:
我怎樣才能內聯彙編使用標籤?
這是最優化形式的拆機輸出:
> gcc -O2 -S main.c
.file "main.c"
.section .text.unlikely,"ax",@progbits
.LCOLDB0:
.text
.LHOTB0:
.p2align 4,,15
.globl swap
.type swap, @function
swap:
.LFB23:
.cfi_startproc
#APP
# 5 "main.c" 1
.intel_syntax noprefix
# 0 "" 2
# 6 "main.c" 1
mov eax, DWORD PTR [rdi]
# 0 "" 2
# 7 "main.c" 1
mov ebx, DWORD PTR [rsi]
# 0 "" 2
# 8 "main.c" 1
cmp eax, ebx
# 0 "" 2
# 9 "main.c" 1
jle 1f
# 0 "" 2
# 10 "main.c" 1
mov DWORD PTR [rdi], ebx
# 0 "" 2
# 11 "main.c" 1
mov DWORD PTR [rsi], eax
# 0 "" 2
# 12 "main.c" 1
1:
# 0 "" 2
# 13 "main.c" 1
.att_syntax noprefix
# 0 "" 2
#NO_APP
ret
.cfi_endproc
.LFE23:
.size swap, .-swap
.section .text.unlikely
.LCOLDE0:
.text
.LHOTE0:
.section .rodata.str1.1,"aMS",@progbits,1
.LC1:
.string "%d%d%d"
.LC2:
.string "%d %d %d\n"
.section .text.unlikely
.LCOLDB3:
.section .text.startup,"ax",@progbits
.LHOTB3:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB24:
.cfi_startproc
subq $40, %rsp
.cfi_def_cfa_offset 48
movl $.LC1, %edi
movq %fs:40, %rax
movq %rax, 24(%rsp)
xorl %eax, %eax
leaq 8(%rsp), %rcx
leaq 4(%rsp), %rdx
movq %rsp, %rsi
call __isoc99_scanf
#APP
# 5 "main.c" 1
.intel_syntax noprefix
# 0 "" 2
# 6 "main.c" 1
mov eax, DWORD PTR [rdi]
# 0 "" 2
# 7 "main.c" 1
mov ebx, DWORD PTR [rsi]
# 0 "" 2
# 8 "main.c" 1
cmp eax, ebx
# 0 "" 2
# 9 "main.c" 1
jle 1f
# 0 "" 2
# 10 "main.c" 1
mov DWORD PTR [rdi], ebx
# 0 "" 2
# 11 "main.c" 1
mov DWORD PTR [rsi], eax
# 0 "" 2
# 12 "main.c" 1
1:
# 0 "" 2
# 13 "main.c" 1
.att_syntax noprefix
# 0 "" 2
# 5 "main.c" 1
.intel_syntax noprefix
# 0 "" 2
# 6 "main.c" 1
mov eax, DWORD PTR [rdi]
# 0 "" 2
# 7 "main.c" 1
mov ebx, DWORD PTR [rsi]
# 0 "" 2
# 8 "main.c" 1
cmp eax, ebx
# 0 "" 2
# 9 "main.c" 1
jle 1f
# 0 "" 2
# 10 "main.c" 1
mov DWORD PTR [rdi], ebx
# 0 "" 2
# 11 "main.c" 1
mov DWORD PTR [rsi], eax
# 0 "" 2
# 12 "main.c" 1
1:
# 0 "" 2
# 13 "main.c" 1
.att_syntax noprefix
# 0 "" 2
# 5 "main.c" 1
.intel_syntax noprefix
# 0 "" 2
# 6 "main.c" 1
mov eax, DWORD PTR [rdi]
# 0 "" 2
# 7 "main.c" 1
mov ebx, DWORD PTR [rsi]
# 0 "" 2
# 8 "main.c" 1
cmp eax, ebx
# 0 "" 2
# 9 "main.c" 1
jle 1f
# 0 "" 2
# 10 "main.c" 1
mov DWORD PTR [rdi], ebx
# 0 "" 2
# 11 "main.c" 1
mov DWORD PTR [rsi], eax
# 0 "" 2
# 12 "main.c" 1
1:
# 0 "" 2
# 13 "main.c" 1
.att_syntax noprefix
# 0 "" 2
#NO_APP
movl 8(%rsp), %r8d
movl 4(%rsp), %ecx
movl $.LC2, %esi
movl (%rsp), %edx
xorl %eax, %eax
movl $1, %edi
call __printf_chk
movq 24(%rsp), %rsi
xorq %fs:40, %rsi
jne .L6
xorl %eax, %eax
addq $40, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 8
ret
.L6:
.cfi_restore_state
call __stack_chk_fail
.cfi_endproc
.LFE24:
.size main, .-main
.section .text.unlikely
.LCOLDE3:
.section .text.startup
.LHOTE3:
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
你試過命名沒有點的標籤嗎?從C生成的裝配標籤通常具有圓點形式。我認爲它可能是保留的。 – PSkocik
後一種解決方案是正確的語法。只是你的代碼無法正常工作而崩潰。 –
@PSkocik是的,我嘗試命名它「CustomLabel1」(沒有點),它仍然給我同樣的錯誤。 –