64位GCC混合32位和64位指针

64位GCC混合32位和64位指针,c,gcc,x86-64,gnu-assembler,C,Gcc,X86 64,Gnu Assembler,虽然代码可以工作,但编译器似乎混合了相同类型的32位和64位参数,这让我感到困惑。具体来说,我有一个函数,它接收三个字符指针。查看汇编代码,三个指针中的两个作为64位指针传递(如预期的那样),而第三个是本地常量,但仍然是字符串,作为32位指针传递。我不知道我的函数如何知道第三个参数不是完全加载的64位指针。显然,只要更高的一方是0,这并不重要,但我不认为它会努力确保这一点。在本例中,任何东西都可能位于RDX的高端。我错过了什么?顺便说一句,接收函数假定它是一个完整的64位指针,并在条目中包含以下

虽然代码可以工作,但编译器似乎混合了相同类型的32位和64位参数,这让我感到困惑。具体来说,我有一个函数,它接收三个字符指针。查看汇编代码,三个指针中的两个作为64位指针传递(如预期的那样),而第三个是本地常量,但仍然是字符串,作为32位指针传递。我不知道我的函数如何知道第三个参数不是完全加载的64位指针。显然,只要更高的一方是0,这并不重要,但我不认为它会努力确保这一点。在本例中,任何东西都可能位于RDX的高端。我错过了什么?顺便说一句,接收函数假定它是一个完整的64位指针,并在条目中包含以下代码:

     movq    %rdx, -24(%rbp)
以下是相关代码:

.LC4
    .string "My Silly String"

    .text
    .globl funky_funk
    .type  funky_funk, @function
    funky_funk:
        pushq     %rbp
            movq      %rsp, %rbp
            pushq     %rbx
            subq      $16, %rsp
            movq      %rdi, -16(%rbp)          ;char *dst 64-bit
            movl      %esi, -20(%rbp)          ;int len, 32 bits OK

            movl      $.LC4, %edx              ;<<<<---- why is it not RDX?

            movl      -20(%rbp), %ecx          ;int len 32-bits OK
            movq      -16(%rbp), %rbx          ;char *dst 64-bit
            movq      -16(%rbp), %rax          ;char *dst 64-bit
            movq      %rbx, %rsi               ;char *dst 64-bit
            movq      %rax, %rdi               ;char *dst 64-bit
            call      edc_function


    void funky_funk(char *dst, int len)
    {                                             //how will function know when 
         edc_function(dst, dst, STRING_LC4, len); //a str passed in 3rd parm
    }                                             //is 32-bit ptr vs 64-bit ptr?

    void edc_function(char *dst, char *src, char *key, int len)
    {
         //so, is key a 32-bit ptr? or is key a 64-bit ptr?
    }
.LC4
.string“我愚蠢的string”
.文本
.globl funky_funk
.type funky_funk,@函数
funky_funk:
pushq%rbp
movq%rsp,%rbp
pushq%rbx
subq$16,%rsp
movq%rdi,-16%(rbp);字符*dst 64位
移动百分比esi,-20%(rbp);整数len,32位正常

movl$.LC4,%edx 在寄存器中加载32位值时,该值为零扩展。您可能在编译器知道代码位于较低32位可寻址内存的模式下工作

GCC有几个用于x64的内存模型,其中两个具有该属性。根据GCC文件:

`-mcmodel=small'
     Generate code for the small code model: the program and its
     symbols must be linked in the lower 2 GB of the address space.
     Pointers are 64 bits.  Programs can be statically or dynamically
     linked.  This is the default code model.
`-mcmodel=medium'
     Generate code for the medium model: The program is linked in the
     lower 2 GB of the address space.  Small symbols are also placed
     there.  Symbols with sizes larger than `-mlarge-data-threshold'
     are put into large data or bss sections and can be located above
     2GB.  Programs can be statically or dynamically linked.
(其他的是内核,类似于small,但在上/负2GB的
地址空间大,无限制)。

添加此作为答案,因为它包含原始问题的“部分谜题”:

.LC4
    .string "My Silly String"

    .text
    .globl funky_funk
    .type  funky_funk, @function
    funky_funk:
        pushq     %rbp
            movq      %rsp, %rbp
            pushq     %rbx
            subq      $16, %rsp
            movq      %rdi, -16(%rbp)          ;char *dst 64-bit
            movl      %esi, -20(%rbp)          ;int len, 32 bits OK

            movl      $.LC4, %edx              ;<<<<---- why is it not RDX?

            movl      -20(%rbp), %ecx          ;int len 32-bits OK
            movq      -16(%rbp), %rbx          ;char *dst 64-bit
            movq      -16(%rbp), %rax          ;char *dst 64-bit
            movq      %rbx, %rsi               ;char *dst 64-bit
            movq      %rax, %rdi               ;char *dst 64-bit
            call      edc_function


    void funky_funk(char *dst, int len)
    {                                             //how will function know when 
         edc_function(dst, dst, STRING_LC4, len); //a str passed in 3rd parm
    }                                             //is 32-bit ptr vs 64-bit ptr?

    void edc_function(char *dst, char *src, char *key, int len)
    {
         //so, is key a 32-bit ptr? or is key a 64-bit ptr?
    }

只要编译器能够[例如通过指定满足此条件的memorymodel]确定.LC4在前4GB内,它就可以这样做edx将加载LC4地址的32位,高位设置为零,因此当调用edc_函数()时,它可以使用%rdx的全部64位,只要地址在较低的4GB范围内,就可以正常工作

只要编译器能够确定.LC4在前4GB之内,它就可以这样做。它看起来确实像一只虫子edx将加载LC4地址的32位,高位设置为零,因此当调用edc_函数()时,它可以使用完整的64位,只要地址在较低的4GB范围内,就可以正常工作。但对我来说确实很奇怪。好吧,我不知道CPU零扩展了负载。唷!这让我可以睡一觉…仅供参考,如果无法进行此优化,下一个最佳选择是
lea.LC4(%rip),%rdx
。不是具有64位绝对地址的10字节mov。好的,我使用的是mcmodel=small,因为它是默认值(除了-O2之外,我没有其他编译器选项)。-mcmodel=small为小代码模型生成代码:程序及其符号必须在地址空间的较低2GB中链接。指针为64位。程序可以静态或动态链接。这是默认代码模型。”但是关于零扩展和编译器知道这个特定字符串的位置这一事实你是对的。@GarysTampaOfficeOfficeTampa,已修复。我在搜索一些不存在的东西,却忽略了刚好在我的起点之上的证明;)我(愚蠢地回顾)假设small与之类似,即长64位的mx32。那么,您的主要答案仍然正确:32位reg在64位模式下是零扩展的。