Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在程序集中声明和索引qwords的整数数组_Arrays_Assembly_X86 64_Att - Fatal编程技术网

Arrays 在程序集中声明和索引qwords的整数数组

Arrays 在程序集中声明和索引qwords的整数数组,arrays,assembly,x86-64,att,Arrays,Assembly,X86 64,Att,我有一个关于如何在程序集中初始化数组的问题。我试过: .bss #the array unsigned: .skip 10000 .data #these are the values that I want to put in the array par4: .quad 500 par5: .quad 10 par6: .quad 15 这就是我如何声明我的字符串和我想放入其中的变量。 这就是我如何将它们放入阵列的方法: movq $0 , %r8 movq par4

我有一个关于如何在程序集中初始化数组的问题。我试过:

.bss
#the array
unsigned:    .skip 10000
.data
#these are the values that I want to put in the array
par4:   .quad 500 
par5:   .quad 10
par6:   .quad 15
这就是我如何声明我的字符串和我想放入其中的变量。 这就是我如何将它们放入阵列的方法:

movq $0 , %r8

movq par4 , %rax
movq %rax , unsigned(%r8)
incq %r8

movq par5 , %rax
movq %rax , unsigned(%r8)
incq %r8

movq par6 , %rax
movq %rax , unsigned(%r8)
我试着打印元素以检查是否一切正常,只有最后一个打印正常,其他两个有一些奇怪的值


也许这不是我应该声明和使用它的方式?

首先,
unsigned
是C中类型的名称,因此它对于数组来说是一个糟糕的选择。让我们把它叫做
arr

您希望将BSS中的空间块视为数组qword元素。所以每个元素是8个字节因此需要存储到
arr+0
arr+8
arr+16
(数组的总大小为10000字节,即10000/8个字)

但是您使用的是
%r8
作为字节偏移量,而不是缩放索引。这通常是一件好事,其他一切都是一样的;在某些CPU上,索引寻址模式在某些情况下较慢。但问题是,您只能使用
inc
将其增加
1
,而不是使用
添加$8,%r8

因此,您实际上是在存储到
arr+0
arr+1
arr+2
,8字节的存储相互重叠,只剩下最后一个存储的最低有效字节。x86是小端字节,因此内存的结果内容实际上是这样的,后面是剩余的未写入字节,它们保持为零

# static array that matches what you actually stored
arr: .byte 500 & 0xFF, 10, 15, 0, 0, 0, 0, 0, 0, 0, ...
当然,您可以使用
.data
部分中的
.qword
来声明包含所需内容的静态数组。但由于只有前3个元素非零,因此将其放入BSS对于这么大的一个元素是有意义的,而不是将操作系统页面置于磁盘的零中


如果要完全展开,而不是从
par4
开始在3元素qword数组上使用循环,则根本不需要增加寄存器。您也不需要将初始值设定项放在数据内存中,您可以使用立即数,因为它们都适合作为32位符号扩展

  # these are assemble-time constants, not associated with a section
.equ par4, 500
.equ par5, 10
.equ par6, 15

.text  # already the default section but whatever

.globl _start
_start:
    movq    $par4, arr(%rip)            # use RIP-relative addressing when there's no register
    movq    $par5, arr+8(%rip)
    movq    $par6, arr+16(%rip)

    mov $60, %eax
    syscall               # Linux exit(0)

.bss
    arr:   .skip 10000
您可以在GDB下运行它并检查内存以查看您得到了什么。(使用gcc-nostlib-static foo.s编译它)。在GDB中,用
starti
启动程序(在入口点停止),然后用
si
单步执行。使用
x/4g&arr
arr
处的内存内容转储为4个qwords的数组

或者,如果您确实想使用寄存器,也可以只循环指针而不是索引

    lea     arr(%rip), %rdi           # or mov $arr, %edi in a non-PIE executable
    movq    $par4, (%rdi)
    add     $8, %rdi                  # advance the pointer 8 bytes = 1 element
    movq    $par5, (%rdi)
    add     $8, %rdi
    movq    $par6, (%rdi)
或按比例索引:

## Scaled-index addressing
    movq    $par4, arr(%rip)
    mov     $1, %eax
    movq    $par5, arr(,%rax,8)       # [arr + rax*8]
    inc     %eax
    movq    $par6, arr(,%rax,8)

有趣的技巧:你可以只做一个字节存储而不是qword存储来设置低位字节,剩下的保持为零。这将节省代码大小,但如果您立即加载qword,您将得到一个商店转发暂停。(~10个周期的额外延迟,用于存储/重新加载将缓存中的数据与存储缓冲区中的存储合并)


或者如果您仍然希望从
.rodata
中的
par4
复制24个字节,则可以使用SSE。x86-64保证SSE2可用

    movaps   par4(%rip), %xmm0
    movaps   %xmm0, arr(%rip)          # copy par4 and par5

    mov      par6(%rip), %rax          # aka par4+16
    mov      %rax, arr+16(%rip)

.section .rodata          # read-only data.
.p2align 4         # align by 2^4 = 16 for movaps
  par4:  .quad 500
  par5:  .quad 10
  par6:  .quad 15

.bss
.p2align 4        # align by 16 for movaps
  arr: .skip 10000
# or use .lcomm arr, 10000  without even switching to .bss
或者使用SSE4.1,您可以加载并扩展小常量,这样就不需要为要复制到BSS阵列中的每个小数字使用一个完整的qword

    movzxwq    initializers(%rip), %xmm0       # zero-extend 2 words into 2 qwords
    movaps     %xmm0, arr(%rip)
    movzwl     initializers+4(%rip), %eax      # zero-extending word load
    mov        %rax, arr+16(%rip)

.section .rodata
  initializers: .word 500, 10, 15

您正在使用
%r8
作为字节偏移量,而
incq%r8
只将其提前1个字节,而不是8个字节。您需要缩放索引寻址模式或
添加$8,%r8
。此外,您还可以通过将数组放入
.data
而不是bss来静态初始化数组,如从
par4
开始的3元素数组。或者您可以使用
.eq
常量并将mov immediate放入内存。这里也不需要增加指针,只需存储到
unsigned
unsigned+8
unsigned+16
。此外,
unsigned
将是一个不方便的符号名称选择,如果您想从C访问数组。
unsigned
是一个关键字,因此您不能声明
外部uint64\u unsigned>[1000/8]
。(我找不到一个合适的规范问答,所以我决定写一个,因为这个问题很短,格式很好,没有其他干扰因素。不过,我知道我已经多次看到这个错误。特别是在英特尔语法中,寻址与扩展索引的C数组索引具有相同的外观。)