You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ASM编写Java本地代码?参数接收异常求助

Troubleshooting JNI Parameter Handling in Windows x64 Assembly

Hey there! As someone who's dug into JNI assembly on Windows, I totally get where you're stuck—this is a super common gotcha because JNI doesn't exactly follow the standard Windows x64 calling convention without extra context. Let's break down what's going wrong and how to fix it.

The Key Difference: JNI's Hidden Prefix Parameters

When Java calls a native method, it doesn't just pass your defined arguments first. JNI always prepends two mandatory parameters to the call stack/registers:

  1. JNIEnv* (passed via rcx in Windows x64)
  2. Either jclass (for static native methods) or jobject (for instance methods, passed via rdx)

Your actual user-defined parameters start after these two. So if you were expecting your first parameter in rcx, that's why it's missing—rcx is holding the JNI environment pointer instead!

Example Parameter Mapping

Let's say your Java native method looks like this:

public native int calculate(int num1, String text); // Instance method

In Windows x64 assembly, the parameters will be mapped like this:

  • rcx: JNIEnv* (required JNI context)
  • rdx: jobject (the instance of your class calling the method)
  • r8: jint num1 (your first user parameter)
  • r9: jstring text (your second user parameter)

If it were a static method, rdx would hold the jclass instead of an instance object.

Don't Forget the Shadow Space!

Windows x64 requires callers to allocate 32 bytes of "shadow space" on the stack for the first four register-passed parameters. Even if you don't use this space, you need to reserve it to maintain proper stack alignment.

In assembly, this means you should start your function with:

sub rsp, 28h ; Reserves 32 bytes of shadow space + ensures 16-byte stack alignment

(Note: After a call instruction, the stack is 8 bytes off alignment, so subtracting 28h brings it back to 16-byte alignment while providing the required shadow space.)

Quick Working Example

Here's a minimal assembly function that returns the first user-defined integer parameter from the example above:

; JNI function name: Java_com_yourpackage_YourClass_calculate
; (Replace with your actual package/class/method name, using underscores for dots)
Java_com_yourpackage_YourClass_calculate proc
    ; Reserve shadow space and align stack
    sub rsp, 28h

    ; Our user parameter num1 is in r8 (jint is 32-bit, so use eax)
    mov eax, r8d ; Move the lower 32 bits of r8 into eax (return register for int)

    ; Clean up stack
    add rsp, 28h
    ret
Java_com_yourpackage_YourClass_calculate endp

Critical Checks to Debug Your Code

  • Verify Function Naming: JNI enforces strict naming rules. For a class com.foo.Bar with method doThing, the function name must be Java_com_foo_Bar_doThing. If your method name has underscores, escape them with another underscore (e.g., do_thing becomes do__thing).
  • Stack Alignment: Windows x64 requires the stack to be 16-byte aligned at all times. Forgetting shadow space or misaligning the stack will cause unpredictable behavior.
  • Debug Register Values: Use a tool like WinDbg to break into your assembly function and inspect the values in rcx, rdx, r8, r9—you'll see the JNIEnv and class/instance pointers first, followed by your parameters.

Hope this clears up the confusion! It's easy to overlook those hidden JNI parameters when you're used to standard C++ calling conventions.

内容的提问来源于stack exchange,提问作者Penelope Hubble

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:31:26