C++ 使用汇编访问数组元素时的SIGSEGV 背景:

C++ 使用汇编访问数组元素时的SIGSEGV 背景:,c++,arrays,segmentation-fault,inline-assembly,gnu-assembler,C++,Arrays,Segmentation Fault,Inline Assembly,Gnu Assembler,我不熟悉集会。当我学习编程时,我做了一个程序,实现了1000*1000的乘法表。表格的格式是这样的,每个答案都在factor1行上,我打赌表格是指向数组的指针,而不是数组本身 因此,您需要: asm volatile ( "shll $10, %1;" movl _tables,%%eax "orl %1, %2;" "movl (%%eax,%2,4)", : "=r" (answer) : "r" (factor1), "r" (

我不熟悉集会。当我学习编程时,我做了一个程序,实现了1000*1000的乘法表。表格的格式是这样的,每个答案都在
factor1行上,我打赌
表格
是指向数组的指针,而不是数组本身

因此,您需要:

 asm volatile ( "shll $10, %1;"
        movl  _tables,%%eax
       "orl %1, %2;"
       "movl (%%eax,%2,4)",
       : "=r" (answer) : "r" (factor1), "r" (factor2) : "eax" )   
(别忘了最后一行的额外打击)

当然也有一些变化,如果代码在循环中,这可能更有效:

 asm volatile ( "shll $10, %1;"
       "orl %1, %2;"
       "movl (%3,%2,4)",
       : "=r" (answer) : "r" (factor1), "r" (factor2), "r"(tables) )   
(从反汇编中)我打赌
是指向数组的指针,而不是数组本身

因此,您需要:

 asm volatile ( "shll $10, %1;"
        movl  _tables,%%eax
       "orl %1, %2;"
       "movl (%%eax,%2,4)",
       : "=r" (answer) : "r" (factor1), "r" (factor2) : "eax" )   
(别忘了最后一行的额外打击)

当然也有一些变化,如果代码在循环中,这可能更有效:

 asm volatile ( "shll $10, %1;"
       "orl %1, %2;"
       "movl (%3,%2,4)",
       : "=r" (answer) : "r" (factor1), "r" (factor2), "r"(tables) )   

这是对Mats Peterson答案的补充——我写这篇文章的原因很简单,因为我不清楚OP对反汇编的分析(他的汇编和编译器生成的汇编是等效的)为什么不正确

正如Mats Peterson所解释的,问题在于
实际上是指向数组的指针,因此要访问元素,必须取消引用两次。现在对我来说,这在编译器生成的代码中发生在哪里还不清楚。罪魁祸首是这条看起来无辜的线:

a1 18 e0 47 00          mov    0x47e018,%eax
对于未经培训的人(包括我的),这可能看起来像值
0x47e018
被移动到
eax
,但实际上不是。相同操作码的英特尔语法表示为我们提供了一个线索:

a1 18 e0 47 00          mov    eax,ds:0x47e018
啊-
ds:
-所以它实际上不是一个值,而是一个地址

对于现在想知道的人,下面是将值
0x47e018
移动到
eax
的操作码和ATT语法汇编:

b8 18 e0 47 00          mov    $0x47e018,%eax

这是对Mats Peterson答案的补充——我写这篇文章的原因很简单,因为我不清楚OP对反汇编的分析(他的汇编和编译器生成的汇编是等效的)为什么不正确

正如Mats Peterson所解释的,问题在于
实际上是指向数组的指针,因此要访问元素,必须取消引用两次。现在对我来说,这在编译器生成的代码中发生在哪里还不清楚。罪魁祸首是这条看起来无辜的线:

a1 18 e0 47 00          mov    0x47e018,%eax
对于未经培训的人(包括我的),这可能看起来像值
0x47e018
被移动到
eax
,但实际上不是。相同操作码的英特尔语法表示为我们提供了一个线索:

a1 18 e0 47 00          mov    eax,ds:0x47e018
啊-
ds:
-所以它实际上不是一个值,而是一个地址

对于现在想知道的人,下面是将值
0x47e018
移动到
eax
的操作码和ATT语法汇编:

b8 18 e0 47 00          mov    $0x47e018,%eax

你为什么要做编译器的工作?@TonyTheLion刚刚读到了一个问题:“我知道使用汇编不会加快很多速度,但我只是想做这件事是为了好玩(还有一点练习)。”“有人想做编译器”听起来更有趣,@Tony.asm volatile的
volatile
部分告诉编译器它根本不能移动程序集的一部分,也不能在程序集周围移动代码的其他部分。这会阻止编译器内置的优化器执行其工作。您不应该将程序集指定为
volatile
,除非您确定需要这样做,并且您了解原因。需要它的一个很好的例子是
rdtsc
,因为您不希望编译器移动该代码,否则它会计时错误。@SoapBox感谢您指出这一点,我将删除它。您为什么要尝试做编译器的工作?@TonyTheLion请阅读以下问题:“我知道使用汇编不会加快很多速度,但我只是想做它的乐趣(和一点练习)。”“有人试图成为一名编译器“听起来很有趣,@Tony.
asm volatile
volatile
部分告诉编译器它根本不能移动程序集的一部分,也不能在程序集周围移动代码的其他部分。这会阻止编译器内置的优化器执行其工作。您不应该将程序集指定为
volatile
,除非您确定需要这样做,并且您了解原因。需要它的一个很好的例子是
rdtsc
,因为您不希望编译器移动该代码,否则它会计时错误。@SoapBox感谢您指出这一点,我将删除它。非常感谢!在
movl
的末尾有一个逗号,使编译器感到困惑。除此之外,它工作得非常好!非常感谢你!在
movl
的末尾有一个逗号,使编译器感到困惑。除此之外,它工作得非常好!
a1 18 e0 47 00          mov    eax,ds:0x47e018
b8 18 e0 47 00          mov    $0x47e018,%eax