C++ 将数学表达式转换为x86程序集无符号与无符号
我正在编写一个表达式计算器,它生成x86 64位程序集。我选择模仿C++编译器规则的变量类型(char to int促销等,和文字值)。然而,我有一个令人困惑的问题。当计算复杂的数学表达式时,我首先使用后缀转换。接下来,在内部跟踪数据类型的同时,逻辑根据转换和/或输入操作数类型跟踪数据类型。我的问题是<强>当符号数变成未签名,反之亦然,由C++编译器< /强>中间表示?在汇编的生产过程中,我注意到ClangAssembly有时会使用movl,因为您可能会认为基于以前的数据类型,指令将是对扩展(movswl)进行签名。一般来说,我希望模仿C++编译器的类型转换以及中间处理的传统。C++ 将数学表达式转换为x86程序集无符号与无符号,c++,assembly,unsigned,signed,C++,Assembly,Unsigned,Signed,我正在编写一个表达式计算器,它生成x86 64位程序集。我选择模仿C++编译器规则的变量类型(char to int促销等,和文字值)。然而,我有一个令人困惑的问题。当计算复杂的数学表达式时,我首先使用后缀转换。接下来,在内部跟踪数据类型的同时,逻辑根据转换和/或输入操作数类型跟踪数据类型。我的问题是当符号数变成未签名,反之亦然,由C++编译器< /强>中间表示?在汇编的生产过程中,我注意到ClangAssembly有时会使用movl,因为您可能会认为基于以前的数据类型,指令将是对扩展(movs
作为一个例子,考虑到我的程序(数据类型模拟C++)的输入:
在C++中,相同的代码产生为:>/P>include <stdio.h>
int main(void) {
short s_A=658;
long long ll_B=293;
unsigned int ui_C=94;
printf("%hi\n",s_A);
printf("%lld\n",ll_B);
printf("%u\n",ui_C);
printf("-------------------------\n");
ll_B=((394)-ui_C*(649)+(917)+ll_B-(80));
printf("%lld\n",ll_B);
printf("-------------------------\n");
printf("%hi\n",s_A);
printf("%lld\n",ll_B);
printf("%u\n",ui_C);
}
.text
.file "/home/anthony/comptest/simple/whole_short_int_longlong_simple/whole_short_int_longlong_simple_33.cpp"
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
pushq %rbp
.Ltmp0:
.cfi_def_cfa_offset 16
.Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp2:
.cfi_def_cfa_register %rbp
subq $64, %rsp
movabsq $.L.str, %rdi
movw $658, -2(%rbp) # imm = 0x292
movq $293, -16(%rbp) # imm = 0x125
movl $94, -20(%rbp)
movswl -2(%rbp), %esi
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movq -16(%rbp), %rsi
movl %eax, -24(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str2, %rdi
movl -20(%rbp), %esi
movl %eax, -28(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str3, %rdi
movl %eax, -32(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movl $394, %esi # imm = 0x18A
imull $649, -20(%rbp), %ecx # imm = 0x289
subl %ecx, %esi
addl $917, %esi # imm = 0x395
movl %esi, %ecx
movl %ecx, %edx
addq -16(%rbp), %rdx
subq $80, %rdx
movq %rdx, -16(%rbp)
movq -16(%rbp), %rsi
movl %eax, -36(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str3, %rdi
movl %eax, -40(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str, %rdi
movswl -2(%rbp), %esi
movl %eax, -44(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movq -16(%rbp), %rsi
movl %eax, -48(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str2, %rdi
movl -20(%rbp), %esi
movl %eax, -52(%rbp) # 4-byte Spill
movb $0, %al
callq printf
xorl %ecx, %ecx
movl %eax, -56(%rbp) # 4-byte Spill
movl %ecx, %eax
addq $64, %rsp
popq %rbp
retq
.Ltmp3:
.size main, .Ltmp3-main
.cfi_endproc
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "%hi\n"
.size .L.str, 5
.type .L.str1,@object # @.str1
.L.str1:
.asciz "%lld\n"
.size .L.str1, 6
.type .L.str2,@object # @.str2
.L.str2:
.asciz "%u\n"
.size .L.str2, 4
.type .L.str3,@object # @.str3
.L.str3:
.asciz "-------------------------\n"
.size .L.str3, 27
.ident "Ubuntu clang version 3.6.2-1 (tags/RELEASE_362/final) (based on LLVM 3.6.2)"
.section ".note.GNU-stack","",@progbits
而gcc生产
.file "whole_short_int_longlong_simple_33.cpp"
.section .rodata
.LC0:
.string "%hi\n"
.LC1:
.string "%lld\n"
.LC2:
.string "%u\n"
.LC3:
.string "-------------------------"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movw $658, -14(%rbp)
movq $293, -8(%rbp)
movl $94, -12(%rbp)
movswl -14(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movl -12(%rbp), %eax
movl %eax, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
movl $.LC3, %edi
call puts
movl -12(%rbp), %eax
imull $649, %eax, %eax
movl $1311, %edx
subl %eax, %edx
movl %edx, %eax
movl %eax, %edx
movq -8(%rbp), %rax
addq %rdx, %rax
subq $80, %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $.LC3, %edi
call puts
movswl -14(%rbp), %eax
movl %eax, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movl -12(%rbp), %eax
movl %eax, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010"
.section .note.GNU-stack,"",@progbits
和叮当声产生:
include <stdio.h>
int main(void) {
short s_A=658;
long long ll_B=293;
unsigned int ui_C=94;
printf("%hi\n",s_A);
printf("%lld\n",ll_B);
printf("%u\n",ui_C);
printf("-------------------------\n");
ll_B=((394)-ui_C*(649)+(917)+ll_B-(80));
printf("%lld\n",ll_B);
printf("-------------------------\n");
printf("%hi\n",s_A);
printf("%lld\n",ll_B);
printf("%u\n",ui_C);
}
.text
.file "/home/anthony/comptest/simple/whole_short_int_longlong_simple/whole_short_int_longlong_simple_33.cpp"
.globl main
.align 16, 0x90
.type main,@function
main: # @main
.cfi_startproc
# BB#0:
pushq %rbp
.Ltmp0:
.cfi_def_cfa_offset 16
.Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp2:
.cfi_def_cfa_register %rbp
subq $64, %rsp
movabsq $.L.str, %rdi
movw $658, -2(%rbp) # imm = 0x292
movq $293, -16(%rbp) # imm = 0x125
movl $94, -20(%rbp)
movswl -2(%rbp), %esi
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movq -16(%rbp), %rsi
movl %eax, -24(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str2, %rdi
movl -20(%rbp), %esi
movl %eax, -28(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str3, %rdi
movl %eax, -32(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movl $394, %esi # imm = 0x18A
imull $649, -20(%rbp), %ecx # imm = 0x289
subl %ecx, %esi
addl $917, %esi # imm = 0x395
movl %esi, %ecx
movl %ecx, %edx
addq -16(%rbp), %rdx
subq $80, %rdx
movq %rdx, -16(%rbp)
movq -16(%rbp), %rsi
movl %eax, -36(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str3, %rdi
movl %eax, -40(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str, %rdi
movswl -2(%rbp), %esi
movl %eax, -44(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str1, %rdi
movq -16(%rbp), %rsi
movl %eax, -48(%rbp) # 4-byte Spill
movb $0, %al
callq printf
movabsq $.L.str2, %rdi
movl -20(%rbp), %esi
movl %eax, -52(%rbp) # 4-byte Spill
movb $0, %al
callq printf
xorl %ecx, %ecx
movl %eax, -56(%rbp) # 4-byte Spill
movl %ecx, %eax
addq $64, %rsp
popq %rbp
retq
.Ltmp3:
.size main, .Ltmp3-main
.cfi_endproc
.type .L.str,@object # @.str
.section .rodata.str1.1,"aMS",@progbits,1
.L.str:
.asciz "%hi\n"
.size .L.str, 5
.type .L.str1,@object # @.str1
.L.str1:
.asciz "%lld\n"
.size .L.str1, 6
.type .L.str2,@object # @.str2
.L.str2:
.asciz "%u\n"
.size .L.str2, 4
.type .L.str3,@object # @.str3
.L.str3:
.asciz "-------------------------\n"
.size .L.str3, 27
.ident "Ubuntu clang version 3.6.2-1 (tags/RELEASE_362/final) (based on LLVM 3.6.2)"
.section ".note.GNU-stack","",@progbits
请注意,问题在rbx寄存器的评估范围内(EBX=32)。因为最后一个操作数是文本,所以我的逻辑在内部将这些值记为有符号int32位。因此,当加宽到64位时,会发出movslq,以符号扩展该值。而gcc(c编译器规则)则通过将32位数据移动到另一个寄存器(0填充上半部分)进行零扩展,然后将其作为64位数字引用
我还想解决另外两个稍微复杂一点的问题(进位、溢出(整数、SSE和FPU)、无符号/有符号等),因此,如果您擅长x86 64上的汇编,我是一个行为良好的对话者。对互联网的研究确实产生了一些与这一主题相关的结果。然而,我还没有找到一个明确的包含这两种恭维理解的文本。第4.5节解释了如何将一个值转换为它自己的类型: 4.5整体促销[conv.prom]
- 除bool、char16\u t、char32\u t或wchar\u t以外的整数类型的PR值,其整数转换秩(4.13)小于 如果int可以表示所有值,则int可以转换为int类型的prvalue 源类型的值;否则,源pr值可以是 已转换为类型为unsigned int的prvalue
- char16\u t、char32\u t或wchar\u t(3.9.1)类型的PR值可转换为以下第一种类型的PR值: 表示其基础类型的所有值:int、unsigned int、, 长整型、无符号长整型、长整型或无符号长整型。 如果该列表中的任何类型都不能表示其 基础类型,类型为char16\u t、char32\u t或wchar\u t的PR值可以 将转换为其基础类型的prvalue
- 基础类型不固定(7.2)的非范围枚举类型的prvalue可以转换为 以下类型可以表示枚举的所有值 (即7.2中所述的最小值至最大值范围内的值): 整型、无符号整型、长整型、无符号长整型、长整型或 无符号长整型。如果该列表中的任何类型都不能 表示枚举的所有值,一个未作用域的值 枚举类型可以转换为扩展整数的prvalue 最小整数转换秩(4.13)大于秩的类型 long的,其中枚举的所有值都可以 代表。如果有两个这样的扩展类型,那么有符号的类型是 选择
- 基础类型为固定(7.2)的非范围枚举类型的prvalue可以转换为其基础类型的prvalue。 此外,如果可以对其基础类型应用积分提升, 非作用域枚举类型的右值,其基础类型为 fixed还可以转换为提升的基础的prvalue 类型
- 如果int可以表示整型位字段(9.6)的所有值,则整型位字段(9.6)的prvalue可以转换为int类型的prvalue 位域;否则,如果为unsigned,则可以将其转换为unsigned int int可以表示位字段的所有值。如果位字段为 更大,但没有整体的推广适用于它。如果位字段 一个枚举类型,它被视为该类型的任何其他值 推广目的
- bool类型的prvalue可以转换为int类型的prvalue,false变为零,true变为一
- 这些转换称为整体促销
C++标准的第5节解释表达式中的提升。 。。。还有很多其他的事情
- 否则,应在两个平台上执行整体促销(4.5)
操作数。[59]则以下规则应适用于
提升的操作数:
- 如果两个操作数的类型相同,则不需要进一步转换 需要
- 否则,如果两个操作数都具有有符号整数类型或都具有 无符号整数类型,类型为较小整数的操作数 转换秩应转换为具有 更高的等级
- 否则,如果具有无符号整数类型的操作数具有秩 大于或等于其他操作数类型的秩, 带符号整数类型的操作数应转换为 无符号整数类型的操作数
- 否则,如果带符号整数类型的操作数的类型
用无符号表示操作数类型的所有值
整数类型,具有无符号整数类型的操作数
ll_B=((394)-ui_C*(649)+(917)+ll_B-(80));
ll_B=394-ui_C*649+917+ll_B-80;