1252-142 由于本地标签,AIX 汇编程序出现语法错误
1252-142 Syntax error from AIX assembler due to local label
我在使用内联汇编和本地标签时遇到汇编错误。编译器是GCC,机器是PowerPC 运行 AIX。代码reads the timestamp(大致相当于rdtsc
):
static unsigned long long cpucycles( void )
{
unsigned long long int result=0;
unsigned long int upper, lower,tmp;
__asm__ __volatile__ (
"0: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- 0b \n\t"
: "=r"(upper),"=r"(lower),"=r"(tmp)
: :
);
result = upper;
result = result<<32;
result = result|lower;
return(result);
}
当代码被汇编时,结果为:
gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 103: 1252-142 Syntax error.
用 --save-temps
编译并检查 test.s
:
$ cat -n test.s
...
101 L..5:
102 # 58 "test.c" 1
103 0:
104 mftbu 10
105 mftb 9
106 mftbu 8
107 cmpw 8,10
108 bne 0b
109
看起来汇编程序在处理本地标签时遇到了问题。基于 IBM 的 Use of inline assembly 和本地标签,我相信标签和分支被正确使用:
Only some local labels are legal in inline assembly. You might see
labels, such as 0 and 1 in Code C. They are the branching target of
instruction bne- 0b\n\t
and bne 1f\n\t
. (The f suffix for the
label means the label behind the branch instruction, and b is for the
one ahead)
IBM 的error message for 1252-142 不是很有帮助:
Cause
If an error occurred in the assembly processing and the error is not
defined in the message catalog, this generic error message is used.
This message covers both pseudo-ops and instructions. Therefore, a
usage statement would be useless.
Action
Determine intent and source line construction, then consult the
specific instruction article to correct the source line.
问题是什么,我该如何解决?
根据@Eric 在评论中的建议:
__asm__ __volatile__ (
"\n0: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- 0b \n\t"
: "=r"(upper),"=r"(lower),"=r"(tmp)
);
导致向下移动一行的问题:
gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 104: 1252-142 Syntax error.
但标签似乎在第 0 列:
103
104 0:
105 mftbu 10
106 mftb 9
107 mftbu 8
108 cmpw 8,10
109 bne- 0b
gcc 不直接生成机器代码;它将其 asm 输出提供给系统汇编程序。您可以将 gcc 配置为使用不同的汇编程序,例如 GAS,但显然您使用的机器上的默认设置是使用 AIX 汇编程序的 GCC。
显然 AIX 的汇编程序不支持数字标签,这与 GNU 汇编程序不同。当您提到使用 0
.
等标签时,您链接的文章可能是假设 Linux(无意或有意)
最简单的解决方法可能是让 GCC 自动为标签编号而不是使用本地标签,这样同一个 asm 块可以在同一个编译单元中多次内联/展开而不会出现符号名称冲突。 %=
expands to a unique number in every instance.
IDK 如果 L..
使其成为文件本地标签(不会弄乱调试信息或符号 table)。在 Linux/ELF/x86 上,.L
是普通前缀,但您有编译器生成的 L..
标签。
__asm__ __volatile__ (
"L..again%=: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- L..again%="
: "=r"(upper),"=r"(lower),"=r"(tmp)
: :
);
或者对于这个特定的 asm 用例,可能有一个读取时间戳寄存器的内置函数,它会像这样编译成 asm。
除了@Peter 的回答外,我刚刚在 上找到了这个答案。另一个问题也遇到了 AIX 上的问题。
这是在 AIX 上导致 1252-142 的另一个问题的代码:
uint32_t val;
__asm__ __volatile__ (
"1: \n" // retry label
#if __BIG_ENDIAN__
".byte 0x7c, 0x60, 0x05, 0xe6 \n" // r3 = darn 3, 0
#else
".byte 0xe6, 0x05, 0x60, 0x7c \n" // r3 = darn 3, 0
#else
"cmpwi 3,-1 \n" // r3 == -1?
"beq 1b \n" // again on failure
"mr %0,3 \n" // val = r3
: "=r" (val) : : "r3", "cc"
);
解决方法是,不要使用标签。只需使用位移:
uint32_t val;
__asm__ __volatile__ (
// "1: \n" // retry label
#if __BIG_ENDIAN__
".byte 0x7c, 0x60, 0x05, 0xe6 \n" // r3 = darn 3, 0
#else
".byte 0xe6, 0x05, 0x60, 0x7c \n" // r3 = darn 3, 0
#else
"cmpwi 3,-1 \n" // r3 == -1?
// "beq 1b \n" // again on failure
"beq .-8 \n" // again on failure
"mr %0,3 \n" // val = r3
: "=r" (val) : : "r3", "cc"
);
在上面的代码中,我需要跳回2条指令重新执行darn 3, 0
。每条指令都是 4 个字节,所以跳转是 -8
。但是,跳转目标需要可重定位,因此使用了表达式 .-8
。点表示 "here".
它适用于 AIX 和 Linux。
我在使用内联汇编和本地标签时遇到汇编错误。编译器是GCC,机器是PowerPC 运行 AIX。代码reads the timestamp(大致相当于rdtsc
):
static unsigned long long cpucycles( void )
{
unsigned long long int result=0;
unsigned long int upper, lower,tmp;
__asm__ __volatile__ (
"0: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- 0b \n\t"
: "=r"(upper),"=r"(lower),"=r"(tmp)
: :
);
result = upper;
result = result<<32;
result = result|lower;
return(result);
}
当代码被汇编时,结果为:
gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 103: 1252-142 Syntax error.
用 --save-temps
编译并检查 test.s
:
$ cat -n test.s
...
101 L..5:
102 # 58 "test.c" 1
103 0:
104 mftbu 10
105 mftb 9
106 mftbu 8
107 cmpw 8,10
108 bne 0b
109
看起来汇编程序在处理本地标签时遇到了问题。基于 IBM 的 Use of inline assembly 和本地标签,我相信标签和分支被正确使用:
Only some local labels are legal in inline assembly. You might see labels, such as 0 and 1 in Code C. They are the branching target of instruction
bne- 0b\n\t
andbne 1f\n\t
. (The f suffix for the label means the label behind the branch instruction, and b is for the one ahead)
IBM 的error message for 1252-142 不是很有帮助:
Cause
If an error occurred in the assembly processing and the error is not defined in the message catalog, this generic error message is used. This message covers both pseudo-ops and instructions. Therefore, a usage statement would be useless.
Action
Determine intent and source line construction, then consult the specific instruction article to correct the source line.
问题是什么,我该如何解决?
根据@Eric 在评论中的建议:
__asm__ __volatile__ (
"\n0: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- 0b \n\t"
: "=r"(upper),"=r"(lower),"=r"(tmp)
);
导致向下移动一行的问题:
gcc -O3 -Wall -Wextra -mcpu=power8 -maltivec test.c -o test.exe
Assembler:
test.s: line 104: 1252-142 Syntax error.
但标签似乎在第 0 列:
103
104 0:
105 mftbu 10
106 mftb 9
107 mftbu 8
108 cmpw 8,10
109 bne- 0b
gcc 不直接生成机器代码;它将其 asm 输出提供给系统汇编程序。您可以将 gcc 配置为使用不同的汇编程序,例如 GAS,但显然您使用的机器上的默认设置是使用 AIX 汇编程序的 GCC。
显然 AIX 的汇编程序不支持数字标签,这与 GNU 汇编程序不同。当您提到使用 0
.
最简单的解决方法可能是让 GCC 自动为标签编号而不是使用本地标签,这样同一个 asm 块可以在同一个编译单元中多次内联/展开而不会出现符号名称冲突。 %=
expands to a unique number in every instance.
IDK 如果 L..
使其成为文件本地标签(不会弄乱调试信息或符号 table)。在 Linux/ELF/x86 上,.L
是普通前缀,但您有编译器生成的 L..
标签。
__asm__ __volatile__ (
"L..again%=: \n\t"
"mftbu %0 \n\t"
"mftb %1 \n\t"
"mftbu %2 \n\t"
"cmpw %2,%0 \n\t"
"bne- L..again%="
: "=r"(upper),"=r"(lower),"=r"(tmp)
: :
);
或者对于这个特定的 asm 用例,可能有一个读取时间戳寄存器的内置函数,它会像这样编译成 asm。
除了@Peter 的回答外,我刚刚在
这是在 AIX 上导致 1252-142 的另一个问题的代码:
uint32_t val;
__asm__ __volatile__ (
"1: \n" // retry label
#if __BIG_ENDIAN__
".byte 0x7c, 0x60, 0x05, 0xe6 \n" // r3 = darn 3, 0
#else
".byte 0xe6, 0x05, 0x60, 0x7c \n" // r3 = darn 3, 0
#else
"cmpwi 3,-1 \n" // r3 == -1?
"beq 1b \n" // again on failure
"mr %0,3 \n" // val = r3
: "=r" (val) : : "r3", "cc"
);
解决方法是,不要使用标签。只需使用位移:
uint32_t val;
__asm__ __volatile__ (
// "1: \n" // retry label
#if __BIG_ENDIAN__
".byte 0x7c, 0x60, 0x05, 0xe6 \n" // r3 = darn 3, 0
#else
".byte 0xe6, 0x05, 0x60, 0x7c \n" // r3 = darn 3, 0
#else
"cmpwi 3,-1 \n" // r3 == -1?
// "beq 1b \n" // again on failure
"beq .-8 \n" // again on failure
"mr %0,3 \n" // val = r3
: "=r" (val) : : "r3", "cc"
);
在上面的代码中,我需要跳回2条指令重新执行darn 3, 0
。每条指令都是 4 个字节,所以跳转是 -8
。但是,跳转目标需要可重定位,因此使用了表达式 .-8
。点表示 "here".
它适用于 AIX 和 Linux。