在GAS程序集中访问calloced数组

时间:2014-09-10 17:50:09

标签: c assembly gas

我有一个C函数,它将一些内存分配给一个数组,该数组将填充自然数字达到某个N.

让我们说,

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

然后我调用了我编写的汇编函数,但是我似乎无法访问数组字段。我设法找到N的值,它位于8(%ebp),我已经用GDB检查它确实等于C代码中的N.

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

我通过使用以下代码

movl 12(%ebp), %esi

EDIT;在调用汇编函数之前,我当然用自然数填充数组。我只是不想在这里输入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

,我如何实际获得该值

2 个答案:

答案 0 :(得分:2)

当你这样做时:

movl 12(%ebp), %esi

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

movl (%esi), %eax

这会将第一个元素移动到%eax中。括号基本上是指&#34;%esi指向&#34;。 int的大小可能是4个字节(您可以使用&#39; sizeof(int)&#39;)进行检查。因此,要访问您可以使用的下一个元素:

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

答案 1 :(得分:0)

稍微修改一下。通过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