从Assembly调用C函数 - 切换调用约定

时间:2017-01-19 09:36:40

标签: c assembly linux-kernel nasm

我有一个Linux x64的汇编应用程序,我通过寄存器将参数传递给函数,因此我使用某种特定的调用约定,在本例中为fastcall。现在我想从程序集应用程序调用一个C函数,比如说,需要10个参数。我是否必须切换到cdecl并通过堆栈传递参数,而不管我的应用程序中的其他地方我通过寄存器传递它们?是否允许在一个应用程序中混合调用约定?

3 个答案:

答案 0 :(得分:2)

当然可以。呼叫约定基于每个功能应用。这是一个非常有效的应用程序:

{
  "name": "elm-webpack-starter",
  "description": "Webpack setup for writing Elm apps",
  "version": "0.8.4",
  "license": "MIT",
  "author": "Peter Morawiec",
  "repository": {
    "type": "git",
    "url": "https://github.com/moarwick/elm-webpack-starter"
  },
  "scripts": {
    "start": "webpack-dev-server --hot --inline --port 8001",
    "build": "rimraf dist && webpack && mv dist/*.eot dist/static/css/ && mv dist/*.woff* dist/static/css/ && mv dist/*.svg dist/static/css/ && mv dist/*.ttf dist/static/css/",
    "reinstall": "npm i rimraf && rimraf node_modules && npm uninstall -g elm && npm i -g elm && npm i && elm package install"
  },
  "devDependencies": {
    "autoprefixer": "^6.3.6",
    "bootstrap-sass": "^3.3.6",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.26.1",
    "elm": "^0.18.0",
    "elm-hot-loader": "^0.5.4",
    "elm-webpack-loader": "^4.1.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.9.0",
    "html-webpack-plugin": "^2.17.0",
    "jquery": "^3.1.0",
    "node-sass": "^4.2.0",
    "postcss-loader": "^1.1.1",
    "rimraf": "^2.5.2",
    "sass-loader": "^4.0.0",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.1",
    "webpack-dev-server": "^1.14.1",
    "webpack-merge": "^2.4.0"
  }
}

答案 1 :(得分:2)

我假设通过 fastcall ,你的意思是SysV ABI使用的amd64调用约定(即Linux使用的),其中前几个参数在rdi中传递,{{1 }和rsi

ABI略显复杂,以下是简化。您可能需要阅读the specification了解详细信息。

一般来说,前几个(最左边的)整数或指针参数放在寄存器rdxrdirsirdxrcx中和r8。浮点参数在r9中传递给xmm0。如果寄存器空间耗尽,则从右到左通过堆栈传递其他参数。例如,要调用具有10个整数参数的函数:

xmm7

你需要这样的代码:

foo(a, b, c, d, e, f, g, h, i, k);

对于您的具体示例,mov $a,%edi mov $b,%esi mov $c,%edx mov $d,%ecx mov $e,%r8d mov $f,%r9d push $k push $i push $h push $g call foo add $32,%rsp

getnameinfo

您将int getnameinfo( const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); 中的sardi中的salenrsi中的hostrdx传递hostlen 1}},rcx中的servr8中的servlen和堆栈中的r9

答案 2 :(得分:-1)

你可以,但你不需要。

__attribute__((fastcall))只要求在寄存器中传递前两个参数 - 无论如何,其他所有参数都会自动传递到堆栈上,就像cdecl一样。这样做是为了不通过选择某个调用约定来限制可以赋予函数的参数数量。

在您的示例中,对于使用fastcall调用约定调用的函数的10个参数,前两个参数将在寄存器中传递,其余8个自动在堆栈上,就像使用标准调用约定一样。

由于您已选择将fastcall用于所有其他功能,因此我没有找到您为某个特定功能更改此功能的原因。