【问题标题】:Passing a pointer to an assembly function将指针传递给汇编函数
【发布时间】:2011-07-08 11:27:07
【问题描述】:

我对汇编编程比较陌生。我正在使用带有 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 放入%eax(或%ebx 等)然后用%p 打印它,我看到它的地址和无符号字符指针“s1”的地址我通过它是一样的。但我怀疑我实际上所做的是获取内存地址,将其转换为整数,然后将该整数放入 someaddress 中。

例如,如果我这样做:

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

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

所以...

  • 如何将指针传入并保持为指针?
  • 如何在汇编中使用该指针的值? (例如,像 C 中的 *ptr

我想查看 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

【问题讨论】:

  • 更新代码的问题:为了打印值,您推送 32 位,而变量只有 8 位。您可以将其扩展到 32 位(这是 C 所做的)或更改格式字符串。请注意,-1543299247 的低 8 位实际上确实计算为 81,正如预期的那样。对于第二次打印和返回:您正在尝试通过编写 (str) 来使用双重取消引用,而 x86 中没有这样的事情。如果你问我,汇编器应该为此抛出一个错误,但它会默默地删除括号。

标签: assembly x86 att


【解决方案1】:

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 中的 &amp; 运算符。例如,这条指令:

    lea 12(%ecx), %edx
    

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

    edx = &(*(ecx + 12))
    

    或更简单地说:

    edx = ecx + 12
    

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

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

    意思是:

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

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

编辑 2:

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

【讨论】:

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