【问题标题】:Accessing calloced array in GAS assembly在 GAS 程序集中访问 c​​alloced 数组
【发布时间】:2014-09-10 17:50:09
【问题描述】:

我有一个 C 函数,它为一个数组分配了一些内存,该数组将被填充到某个 N 以内的自然数。

让我们说,

N = 10;
array = calloc(N, sizeof(int));

然后我调用我编写的汇编函数,但是我似乎无法访问数组字段。我设法找到位于 8(%ebp) 处的 N 的值,并且我已与 GDB 核对它确实等于 C 代码中设置的 N。

但是,当我尝试访问数组中的第一个元素并将其移动到例如 %esi 时,该值不是应为的零。

我使用下面的代码来做

movl 12(%ebp), %esi

编辑;在调用汇编函数之前,我当然会用自然数填充数组。我只是不想在这里输入 for 循环。

据我了解,括号取消引用数组的第一个元素,并将其复制到 esi,但是,当我在 GDB 中此代码之后设置的断点上使用信息寄存器时,esi 仅包含一个巨大的负数。

那么,我如何访问预先调用并传递给汇编函数的数组?是否不能取消引用并复制该单个元素?

这是调用汇编函数的 C 函数

int main(int argc, char *argv[]){

    int n = 10;

    int *array = calloc(n, sizeof(int));
    int i, j;

    // Populate array up to N
    for(i = 0; i < n; i++){
        array[i] = 2 + i;
    }

    printf("Array: %d \n", sizeof(array));

    // Run sievs
    sievs_assembly(n, array);

    // print prime
    print_prime(array, n);

    // Free mem
    free(array);

    return EXIT_SUCCESS;
}

我不想发布整个程序集文件,因为它是一个学校项目,我不寻求帮助解决评估,只寻求具体问题。如何取消对数组项的引用。

函数原型是

extern void sievs_assembly(int n, int *a);

我认为由于指针 *a 是一个 int 数组,并且第一个参数 N 位于 8(%ebp),所以第一个数组元素将是 12(%ebp)。

如果仅执行 movl 12(%ebp), %esi 还不够,我该如何获得该值

【问题讨论】:

  • 你没有展示你的功能,甚至没有展示它的原型。我将假设您正在传递一个指针,因此您需要取消引用。 12(%ebp) 仅取消引用 ebp 以获取参数,它不会取消引用指针本身。
  • 我将编辑并发布所有内容。原型是 func(int n, int *a)
  • 如何取消对指针本身的引用?
  • 到目前为止,您已经将指针加载到%esi,要取消引用它,请执行movl (%esi), %esi。旁注:根据标准调用约定,您必须保留esi(以及其他),因此请确保这样做。
  • 是的,例如使用movl $42, (%esi)。这是假设esi 仍然持有指针,即。你还没有在那里加载一个值。

标签: c assembly gnu-assembler


【解决方案1】:

当你这样做时:

movl 12(%ebp), %esi

您已将阵列的内存地址移至 %esi。第一个元素的值就是这个地址所指向的。为此,您可以使用:

movl (%esi), %eax

这会将第一个元素移动到 %eax。括号基本上表示“%esi 指向的内容”。 int 的大小对您来说可能是 4 个字节(您可以使用 'sizeof(int)' 进行检查)。因此,要访问您可以使用的下一个元素:

movl 4(%esi), %eax

将下一个元素移动到 %eax。

我还制作了一个示例程序,它从数组中打印 2 个值。注意:我是为 windows 做的。

.macro print str         #macro name is 'print'. 1 argument: 'str'
    pushl \str           #argument names are escaped
    call _printf
    addl $4, %esp        #pop the arguments
.endm

.macro printf str fs     #can't overload macro names, so let's call this one 'printf'
    pushl \str
    pushl \fs            #printing numbers requires a format srting
    call _printf
    addl $8, %esp
.endm

.text
.global _main

_main:                  #actual program, '_main' becomes 'WinMain@16'
    pushl %ebp          #push frame
    movl %esp, %ebp

    movl $array, %esi   #Move array pointer to $esi.

    #print what %esi is pointing to
    printf (%esi), $fs

    #print a newline
    print $nl

    #print what %esi+4 is pointing to. Since a long is 4 bytes
    #The next element of the array is 4 bytes further than the first
    printf 4(%esi), $fs

    movl $0, %eax       #move 0 to return register
    leave               #pop frame
    ret                 #return

.data

fs: .string "%i"    #Format string
nl: .string "\n"    #New Line

array:              #Some array
    .long 1,2

这个程序打印输出:

1
2

编辑: 由于这引起了一些关注,我想我会用一些宏来更新答案。

并解释c库调用和main上的_前缀;我正在使用 MinGW 在 Windows 上进行编译,这需要这些前缀以避免出现未定义的引用错误。在 linux 上它们是不需要的。

有关macros 和 GAS 的更多文档,请参阅:using as

【讨论】:

  • 谢谢。我唯一的困惑是如何访问指针。我认为我可以在一条指令中做到这一点,但似乎我首先必须移动内存地址,然后再取消引用它。此外,当更改指针中的值时,就像将值移动到取消引用的内存地址一样简单。还是谢谢
  • 我不太确定你已经知道多少,因为你没有发布任何汇编代码(虽然很容易理解)。所以我想我会尽量做到彻底,以确保你理解一切:)。其次,我还考虑了其​​他用户可能会看这个,但不像你那样了解,所以这是我包含(有点过分)示例的另一个原因。第三,我认为任何转移的知识都应该有一个例子,这样你就可以将新知识与你已经知道的东西联系起来。不管怎样,我很高兴能帮上忙
【解决方案2】:

稍作修改。通过 gcc -m32 -g -o foo foo.s 编译它

.data

fs: .string "%i"    #Format string
nl: .string "\n"    #New Line

array: .long 1,2

.text
.global main

main:

pushl %ebp          #push frame
movl %esp, %ebp

movl $array, %esi   #Move array pointer to $esi.

pushl (%esi)        #Push what %esi is pointing to
pushl $fs           #push the format string
call printf        #call printf
addl $8, %esp       #pop the arguments

pushl $nl           #print a new line
call printf
addl $4, %esp

pushl 4(%esi)       #push what %esi+4 is pointing to. Since a long is 4 bytes
pushl $fs           #The next element is 4 bytes further than the first
call printf
addl $8, %esp

pushl $nl           #print a new line
call printf
addl $4, %esp

pushl $0
call exit

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多