10

我对汇编编程很陌生。我正在使用带有 GCC (Linux) 的 x86 平台。

我有一个我想从 C 调用的函数:

myfunc ( unsigned char * s1, unsigned char * s2, int someint );

该函数将获取 s1 和 s2 内存位置并比较它们,然后递增和比较等,同时进行一些处理。这有点像 memcmp,但我做得更多。

我的问题:如果我将指针传递给汇编函数?然后我怎么说“给我存储在这个内存地址的值”?

这是我到目前为止所拥有的:

为了从堆栈中取出第一个函数 arg ("s1"),我这样做(someaddress 是一个 32 位整数,我正在使用 32 位处理器):

movl  8(%esp), %ecx
movl  %ecx, someaddress

如果我放入somevar( %eaxor%ebx等) 然后用 printf 它%p,我看到它的地址和s1我传递的 unsigned char 指针 "" 的地址是相同的。但我怀疑我实际上所做的是获取内存地址,将其转换为整数,然后将该整数放入某个地址。

例如,如果我这样做:

movl  pos1, %eax
movl  pos2, %ebx
cmp   (%eax),(%ebx)

我得到“错误:`cmp' 的内存引用过多”。我不完全确定这意味着什么,除了“你搞砸了”;-)

所以...

  • 如何传递一个指针并将其保留为指针?
  • 如何在汇编中使用所述指针的值?(例如,就像*ptr在 C 中一样)

我要查看 LEA 操作数吗?

我使用 Richard Blum 的“Professional Assembly Programming”作为我的指南,但 Blum 似乎没有涵盖这种情况。

更新

非常感谢您的学习回复!

不幸的是,我仍然无法取消引用。

这是一个简化的例子。汇编函数接受一个指针并且应该回显它。相反,我得到:

first_ptr points to 81 (should be 81) <-- from C program
the value is -1543299247 <-- printf called from within assembler
the value is -6028513 <-- printf called from within assembler
my function returned -6028513 <-- return value printed from C program

C程序:

#include <stdio.h>
#include <string.h>

int main (void) {
        unsigned char first;
        unsigned char * first_ptr;

        first = 'Q';
        first_ptr = &first;

        printf ("first_ptr points to %i (should be 81)\n",*first_ptr);

        printf ("my function returned %i\n", myfunc(first_ptr));
        return 0;
}

组装程序:

.section .data

msg:
  .asciz "the value is %i\n"

.section .bss
.lcomm str, 8

.section .text
.type myfunc, @function
.globl myfunc
myfunc:

  # save stack
  pushl %ebp
  movl  %esp, %ebp

  # save string arg from stack to "str"
  movl  8(%esp), %ecx
  movl  %ecx, str

  # let's try printing the ecx dereference

  pushl (%ecx)
  pushl $msg
  call printf

  # put the value of str on the stack 
  # and call printf

  pushl (str)
  pushl $msg
  call printf

  # now return the character at pos1
  movl  (str), %eax

  # restore the stack
  movl  %ebp, %esp
  popl  %ebp

  ret
4

1 回答 1

8

至少一个操作数cmp必须是寄存器。如果您尝试比较两个内存位置的内容,则需要将其中一个放在寄存器中。如何将其放入您询问的寄存器中?好吧,您已经使用示例代码完成了该操作。这一行:

movl  8(%esp), %ecx

在 %esp+8 处获取 4 个字节并将它们放入 %ecx。在类似 C 的伪代码中:

ecx = *(esp + 8);

希望这是有道理的。您可以执行类似的操作以将指针从堆栈中取出并放入寄存器,然后取消引用它们,比较取消引用的值等等。如果您有更多问题,请告诉我!

编辑-您提出的问题:

  1. 如何传递一个指针并将其保留为指针?

    你已经在这样做了,你的movl 8(%esp), %ecx指令,或者类似的东西会做你需要的一切。

  2. 如何在汇编中使用所述指针的值?(例如,像 C 中的 *ptr)

    您需要()再次使用 - 从上面的指令中加载指针中的第一个字节%ecx,例如:

    movb (%ecx), %edx
    

    在类似于我上面使用的类似 C 的伪代码中,这条指令是:

    edx = *(unsigned char *)ecx;
    
  3. 我要查看 LEA 操作数吗?

    根据您提供的问题描述,可能不会。不过,这总是可能的。 lea工作原理类似于&C 中的运算符。例如,此指令:

    lea 12(%ecx), %edx
    

    可以翻译成我们的伪代码如下:

    edx = &(*(ecx + 12))
    

    或更简单地说:

    edx = ecx + 12
    

    这个例子有点傻,因为我们使用的是一种相对简单的寻址模式,但是这样的事情怎么样:

    lea 1(%edx,%ecx,4), %eax
    

    意思是:

    eax = &(edx[ecx * 4] + 1)
    

通常,解决这类问题的最简单方法是用 C 语言编写例程,然后对其进行编译并反汇编结果。

编辑2:

您的示例程序似乎几乎是正确的,但是您正在尝试取消引用内存中的指针-首先将这些指针放入寄存器中,您应该没问题。

于 2011-03-04T00:21:14.410 回答