标签: calling-convention

汇编 - 将参数传递给函数调用

我目前正在通过反汇编C程序并试图了解它们的作用来进行汇编阅读.

我被困在一个简单的问题:一个简单的你好世界计划.

#include <stdio.h>
#include <stdlib.h>

int main() {
  printf("Hello, world!");
  return(0);
}
Run Code Online (Sandbox Code Playgroud)

当我拆卸主要时:

(gdb) disassemble main
Dump of assembler code for function main:
   0x0000000000400526 <+0>: push   rbp
   0x0000000000400527 <+1>: mov    rbp,rsp
   0x000000000040052a <+4>: mov    edi,0x4005c4
   0x000000000040052f <+9>: mov    eax,0x0
   0x0000000000400534 <+14>:    call   0x400400 <printf@plt>
   0x0000000000400539 <+19>:    mov    eax,0x0  
   0x000000000040053e <+24>:    pop    rbp
   0x000000000040053f <+25>:    ret
Run Code Online (Sandbox Code Playgroud)

我理解前两行:基本指针保存在堆栈上(通过push rbp,这会导致堆栈指针的值减少8,因为它已经"增长")并且堆栈指针的值被保存在基指针中(这样,参数和局部变量可以分别通过正偏移和负偏移轻松到达,而堆栈可以保持"增长").

第三行提出了第一个问题:为什么0x4005c4("Hello,World!"字符串的地址)在edi寄存器中移动而不是在堆栈中移动?printf函数不应该将该字符串的地址作为参数吗?据我所知,函数从堆栈中获取参数(但在这里,看起来参数放在该寄存器中:edi)

在StackOverflow上的另一篇文章中,我读到"printf @ ptl"就像一个调用真正的printf函数的存根函数.我试图反汇编这个功能,但它变得更加混乱:

(gdb) disassemble printf
Dump of assembler code for function __printf:
   0x00007ffff7a637b0 <+0>: sub    rsp,0xd8
   0x00007ffff7a637b7 <+7>: test   al,al …
Run Code Online (Sandbox Code Playgroud)

linux assembly x86-64 abi calling-convention

0
推荐指数
1
解决办法
2397
查看次数

如何使用 Rcpp 处理 R 和 C++ 中调用约定的不匹配?

我正在开发一个带有 C++ 函数的 R 包。我使用 Rcpp。编写和测试时一切正常。但是,当我完成并循环运行它时,我偶尔会收到以下警告和错误: 警告和错误

警告:“.Call”中的堆栈不平衡,78 然后是 77

警告:'{' 中的堆栈不平衡,75 然后是 74

警告:“.Call”中的堆栈不平衡,78 然后是 79

警告:'{' 中的堆栈不平衡,75 然后是 76

警告:“.Call”中的堆栈不平衡,78 然后是 77

警告:'{' 中的堆栈不平衡,75 然后是 74

所以我用谷歌搜索堆栈不平衡,我发现:

什么是堆栈不平衡?

本文指出堆栈不平衡通常是由语言之间调用约定的差异(不匹配)引起的。据我所知,callng约定是调用者函数删除局部变量还是被调用者函数删除的约定。

我发现了这个:

http://www.stats.uwo.ca/faculty/murdoch/software/compilingDLLs/

它说 R 正在使用cdecl而 C++ 使用stdcall.

“如果您的函数使用了stdcall而不是cdecl,则返回时可能会发生崩溃,因为您的参数将在它们已经消失后从堆栈中删除。”

如果我在声明中犯了任何错误,请告诉我。

这是我的 R 代码调用的 C++ 函数:

//[[Rcpp::export]]
int compute(SEXP p_in, Rcpp::NumericVector a) {
    Rcpp::XPtr<emcdf> p(p_in);
    p->cdf(a);
    return p->getResult();
}
//p_in is an external pointer(pointer to an emcdf object in C++)
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,我该如何解决这个问题?

我感谢您的帮助。

更多细节和代码 2.14.2017 …

c++ r calling-convention rcpp

0
推荐指数
1
解决办法
330
查看次数

为什么 rax 和 rdi 在这种情况下工作相同?

我已经做了这个代码:

global  strlen
    ; int strlen(const char *string);
strlen:
    xor     rcx, rcx

retry:
    cmp byte    [rdi + rcx], 0
    je      result
    inc     rcx
    jmp     retry

result:
    mov     rax, rcx
    ret
Run Code Online (Sandbox Code Playgroud)

这就是我测试它的方式:

#include <stdio.h>

int main(int argc, char **argv)
{
    char* bob = argv[1];
    printf("%i\n", strlen(bob));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是一个有效的 strlen,这里没问题,但我注意到我可以rdi在重试块的第一行切换arax而不改变任何东西,我不知道这是否是正常行为。我应该保留哪些值?

assembly x86-64 calling-convention undefined-behavior

0
推荐指数
1
解决办法
631
查看次数

鉴于前两个参数是动态数组,如何访问函数的最后一个参数的值?

C中的函数是

void f(int* out, int* in, int nbElements){
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

由于int nbElements是第一个被压入堆栈in并且out具有可变大小,我如何访问 的值nbElements?据我了解,堆栈看起来像这样:

          esp
          ebp
     return address         # -4(%ebp) 
1st element of int* out     # -8(%ebp)
1st element of int* in      # (%ebp - 8 - 4*nbElements)
      nbElements            # not sure how I can access the value of this
Run Code Online (Sandbox Code Playgroud)

那么如何在nbElements不知道其地址的情况下访问的值呢?

x86 assembly gnu-assembler calling-convention att

0
推荐指数
1
解决办法
55
查看次数

为什么被调用者不首先使用调用者保存的寄存器?

我们知道,根据 x86-64 约定,寄存器%rbx%rbp%r12%r15被归类为被调用者保存的寄存器。While%r10%r111是调用者保存的寄存器。但是当我在大多数情况下编译 C 代码时,例如函数P调用Q,我看到以下函数的汇编代码Q

Q:
   push %rbx
   movq %rdx, %rbx
   ...
   popq %rbx
   ret
Run Code Online (Sandbox Code Playgroud)

我们知道,由于%rbx是一个被调用者保存的寄存器,我们必须将它存储在堆栈中,并在P以后为调用者恢复它。

但它不会更简洁并通过使用调用者保存的寄存器来保存堆栈操作%r10

Q:
   movq %rdx, %r10
   ...
   ret
Run Code Online (Sandbox Code Playgroud)

所以被调用者不需要担心保存和恢复调用者的寄存器,因为调用者在调用被调用者之前已经把它推到了堆栈?

c assembly x86-64 calling-convention compiler-optimization

0
推荐指数
1
解决办法
167
查看次数

这个汇编函数如何返回值?

我用 C 语言编写了一个非常简单的函数,它使用strlen()from<string.h>返回变量的长度char*

int length(char *str) {

    return strlen(str);
}
Run Code Online (Sandbox Code Playgroud)

以下是相应的 x86_64 程序集objdump -M intel -d a.out

00000000000011a8 <length>:
    11a8:   f3 0f 1e fa             endbr64 
    11ac:   55                      push   rbp
    11ad:   48 89 e5                mov    rbp,rsp
    11b0:   48 83 ec 10             sub    rsp,0x10
    11b4:   48 89 7d f8             mov    QWORD PTR [rbp-0x8],rdi
    11b8:   48 8b 45 f8             mov    rax,QWORD PTR [rbp-0x8]
    11bc:   48 89 c7                mov    rdi,rax
    11bf:   e8 ac fe ff ff …
Run Code Online (Sandbox Code Playgroud)

c assembly x86-64 calling-convention

0
推荐指数
1
解决办法
959
查看次数

x86_64 Linux 系统的 GCC 调用约定

我编写了一个最小函数来测试是否可以调用/链接 C 和 x86_64 汇编代码。

这是我的main.c

#include <stdio.h>

extern int test(int);

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

    int a = 10;
    
    int b = test(a);

    printf("b=%d\n", b);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是我的test.asm

section .text
    global test

test:
    mov ebx,2
    add eax,ebx
    ret
Run Code Online (Sandbox Code Playgroud)

我使用这个脚本构建了一个可执行文件

#!/usr/bin/env bash

nasm -f elf64 test.asm -o test.o

gcc -c main.c -o main.o

gcc main.o test.o -o a.out
Run Code Online (Sandbox Code Playgroud)

我写的时候test.asm并没有任何真正的线索我在做什么。然后我离开并做了一些阅读,现在我不明白我的代码是如何工作的,因为我说服自己它不应该这样。

以下是我认为这不起作用的原因列表:

  • 我不保存或恢复基指针(设置堆栈帧)。我实际上不明白为什么需要这样做,但我看过的每个例子都是这样做的。
  • Linux 系统上 gcc 编译器的调用约定应该是通过堆栈传递参数。这里我假设参数是使用eaxand传递的ebx。我认为这是不对的。
  • ret可能希望从某个地方获取返回地址。我相当确定我没有提供这个。
  • 甚至可能还有其他我不知道的原因。

我所编写的内容产生正确的输出完全是侥幸吗?

我对此完全陌生。虽然我顺便听说过一些 …

c linux gcc x86-64 calling-convention

0
推荐指数
1
解决办法
1196
查看次数

为什么这段代码打印由 clang 和 gcc 编译的不同值?

汇编:

.intel_syntax noprefix
.global Foo
Foo:
    mov ax, 146
    ret
Run Code Online (Sandbox Code Playgroud)

主要.c:

#include <stdio.h>

extern int Foo(void);

int main(int argc, char** args){
    printf("Asm returned %d\n", Foo());
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在我编译并链接:

(compiler name) -c asm.s -o asm.o
(compiler name) asm.o main.c -o  main
./main
Run Code Online (Sandbox Code Playgroud)

我正在使用 Windows 和 LLVM 的 x64 windows 二进制文件。

GCC 打印 146(如预期),但 clang 生成的代码打印随机值,为什么?在 Windows 上使用 gdb 调试 clang 二进制文件显然存在一些问题,因此我无法提供任何 gdb 日志。GCC 二进制文件正在执行我期望的操作,但不是 Clang。

c assembly x86-64 calling-convention

0
推荐指数
1
解决办法
86
查看次数

方法链如何工作?

如何在下面的例子中getRequestDispatcher("xxx")调用getServletContext()?这样的调用程序如何工作?请给我一个关于这个背景的清晰图片.

RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
dispatcher.include(request, response);
Run Code Online (Sandbox Code Playgroud)

java jsp servlets calling-convention method-call

-1
推荐指数
1
解决办法
612
查看次数