too many memory references for `mov' when calling a golang function with C by using inline assembly












2















I'm trying to call a golang function from my C code. Golang does not use the standard x86_64 calling convention, so I have to resort to implementing the transition myself. As gcc does not want to mix cdecl with the x86_64 convention,
I'm trying to call the function using inline assembly:



void go_func(struct go_String filename, void* key, int error){
void* f_address = (void*)SAVEECDSA;
asm volatile(" sub rsp, 0xe0; tn
mov [rsp+0xe0], rbp; tn
mov [rsp], %0; tn
mov [rsp+0x8], %1; tn
mov [rsp+0x18], %2; tn
call %3; tn
mov rbp, [rsp+0xe0]; tn
add rsp, 0xe0;"
:
: "g"(filename.str), "g"(filename.len), "g"(key), "g"(f_address)
: );
return;
}


Sadly the compiler always throws an error at me that I dont understand:



./code.c:241: Error: too many memory references for `mov'


This corresponds to this line: mov [rsp+0x18], %2; tn If I delete it, the compilation works. I don't understand what my mistake is...



I'm compiling with the -masm=intel flag so I use Intel syntax. Can someone please help me?










share|improve this question

























  • Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

    – Peter Cordes
    Nov 21 '18 at 21:58
















2















I'm trying to call a golang function from my C code. Golang does not use the standard x86_64 calling convention, so I have to resort to implementing the transition myself. As gcc does not want to mix cdecl with the x86_64 convention,
I'm trying to call the function using inline assembly:



void go_func(struct go_String filename, void* key, int error){
void* f_address = (void*)SAVEECDSA;
asm volatile(" sub rsp, 0xe0; tn
mov [rsp+0xe0], rbp; tn
mov [rsp], %0; tn
mov [rsp+0x8], %1; tn
mov [rsp+0x18], %2; tn
call %3; tn
mov rbp, [rsp+0xe0]; tn
add rsp, 0xe0;"
:
: "g"(filename.str), "g"(filename.len), "g"(key), "g"(f_address)
: );
return;
}


Sadly the compiler always throws an error at me that I dont understand:



./code.c:241: Error: too many memory references for `mov'


This corresponds to this line: mov [rsp+0x18], %2; tn If I delete it, the compilation works. I don't understand what my mistake is...



I'm compiling with the -masm=intel flag so I use Intel syntax. Can someone please help me?










share|improve this question

























  • Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

    – Peter Cordes
    Nov 21 '18 at 21:58














2












2








2








I'm trying to call a golang function from my C code. Golang does not use the standard x86_64 calling convention, so I have to resort to implementing the transition myself. As gcc does not want to mix cdecl with the x86_64 convention,
I'm trying to call the function using inline assembly:



void go_func(struct go_String filename, void* key, int error){
void* f_address = (void*)SAVEECDSA;
asm volatile(" sub rsp, 0xe0; tn
mov [rsp+0xe0], rbp; tn
mov [rsp], %0; tn
mov [rsp+0x8], %1; tn
mov [rsp+0x18], %2; tn
call %3; tn
mov rbp, [rsp+0xe0]; tn
add rsp, 0xe0;"
:
: "g"(filename.str), "g"(filename.len), "g"(key), "g"(f_address)
: );
return;
}


Sadly the compiler always throws an error at me that I dont understand:



./code.c:241: Error: too many memory references for `mov'


This corresponds to this line: mov [rsp+0x18], %2; tn If I delete it, the compilation works. I don't understand what my mistake is...



I'm compiling with the -masm=intel flag so I use Intel syntax. Can someone please help me?










share|improve this question
















I'm trying to call a golang function from my C code. Golang does not use the standard x86_64 calling convention, so I have to resort to implementing the transition myself. As gcc does not want to mix cdecl with the x86_64 convention,
I'm trying to call the function using inline assembly:



void go_func(struct go_String filename, void* key, int error){
void* f_address = (void*)SAVEECDSA;
asm volatile(" sub rsp, 0xe0; tn
mov [rsp+0xe0], rbp; tn
mov [rsp], %0; tn
mov [rsp+0x8], %1; tn
mov [rsp+0x18], %2; tn
call %3; tn
mov rbp, [rsp+0xe0]; tn
add rsp, 0xe0;"
:
: "g"(filename.str), "g"(filename.len), "g"(key), "g"(f_address)
: );
return;
}


Sadly the compiler always throws an error at me that I dont understand:



./code.c:241: Error: too many memory references for `mov'


This corresponds to this line: mov [rsp+0x18], %2; tn If I delete it, the compilation works. I don't understand what my mistake is...



I'm compiling with the -masm=intel flag so I use Intel syntax. Can someone please help me?







c go inline-assembly calling-convention






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 0:03









Michael Petch

25.2k556101




25.2k556101










asked Nov 13 '18 at 18:15









reijinreijin

637




637













  • Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

    – Peter Cordes
    Nov 21 '18 at 21:58



















  • Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

    – Peter Cordes
    Nov 21 '18 at 21:58

















Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

– Peter Cordes
Nov 21 '18 at 21:58





Post your answer as an answer, not an edit to the question. And BTW, you can use push if you simply change the number that you sub from RSP to account for it. Your "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler that the call-clobbered registers are clobbered, and you step on the red-zone because you don't sub enough stack space to go past it.

– Peter Cordes
Nov 21 '18 at 21:58












2 Answers
2






active

oldest

votes


















2














A "g" constraint allows the compiler to pick memory or register, so obviously you'll end up with mov mem,mem if that happens. mov can have at most 1 memory operand. (Like all x86 instructions, at most one explicit memory operand is possible.)



Use "ri" constraints for the inputs that will be moved to a memory destination, to allow register or immediate but not memory.



Also, you're modifying RSP so you can't safely use memory source operands. The compiler is going to assume it can use addressing modes like [rsp+16] or [rsp-4]. So you can't use push instead of mov.





You also need to declare clobbers on all the call-clobbered registers, because the function call will do that. (Or better, maybe ask for the inputs in those call-clobbered registers so the compiler doesn't have to bounce them through call-preserved regs like RBX. But you need to make those operands read/write or declare separate output operands for the same registers to let the compiler know they'll be modified.)



So probably your best bet for efficiency is something like



int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**

asm("sub rsp, 0xe0nt" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] nt"
"push %[fn_str] nt"
"call nt"
"add rsp, 0xe0 + 3*8 nt" // pop red-zone skip space + pushed args

// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);


Notice that the output are not early-clobber, so the compiler can (at its option) use those registers for inputs, but we're not forcing it so the compiler is still free to use some other register or an immediate.



Upon further discussion, Go functions don't clobber RBP, so there's no reason to save/restore it manually. The only reason you might have wanted to is that locals might use RBP-relative addressing modes, and older GCC made it an error to declare a clobber on RBP when compiling without -fomit-frame-pointer. (I think. Or maybe I'm thinking of EBX in 32-bit PIC code.)





Also, if you're using the x86-64 System V ABI, beware that inline asm must not clobber the red-zone. The compiler assumes that doesn't happen and there's no way to declare a clobber on the red zone or even set -mno-redzone on a per-function basis. So you probably need to sub rsp, 128 + 0xe0. Or 0xe0 already includes enough space to skip the red-zone if that's not part of the callee's args.






share|improve this answer


























  • Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

    – reijin
    Nov 14 '18 at 0:10








  • 1





    @reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

    – Peter Cordes
    Nov 15 '18 at 12:50






  • 1





    @reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

    – Peter Cordes
    Nov 15 '18 at 14:29






  • 1





    @reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

    – Peter Cordes
    Nov 15 '18 at 14:32








  • 1





    @reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

    – Peter Cordes
    Nov 15 '18 at 14:39





















0














The original poster added this solution as an edit to their question:



If someone ever finds this, the accepted answer does not help you when you try to call golang code with inline asm! The accepted answer only helps with my initial problem, which helped me to fix the golangcall. Use something like this:**



void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; tn
mov [rsp], %[p1]; tn
mov [rsp+0x8], %[p2]; tn
mov [rsp+0x10], %[p3]; tn
mov [rsp+0x18], %[p4]; tn
call %[func_addr]; tn
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}





share|improve this answer





















  • 1





    This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

    – Peter Cordes
    Nov 21 '18 at 23:01













  • @PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

    – Michael Petch
    Nov 22 '18 at 0:01













  • @PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

    – reijin
    Nov 22 '18 at 17:00













  • @reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

    – Peter Cordes
    Nov 22 '18 at 17:55








  • 2





    @reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

    – Peter Cordes
    Nov 22 '18 at 17:58











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287194%2ftoo-many-memory-references-for-mov-when-calling-a-golang-function-with-c-by-us%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














A "g" constraint allows the compiler to pick memory or register, so obviously you'll end up with mov mem,mem if that happens. mov can have at most 1 memory operand. (Like all x86 instructions, at most one explicit memory operand is possible.)



Use "ri" constraints for the inputs that will be moved to a memory destination, to allow register or immediate but not memory.



Also, you're modifying RSP so you can't safely use memory source operands. The compiler is going to assume it can use addressing modes like [rsp+16] or [rsp-4]. So you can't use push instead of mov.





You also need to declare clobbers on all the call-clobbered registers, because the function call will do that. (Or better, maybe ask for the inputs in those call-clobbered registers so the compiler doesn't have to bounce them through call-preserved regs like RBX. But you need to make those operands read/write or declare separate output operands for the same registers to let the compiler know they'll be modified.)



So probably your best bet for efficiency is something like



int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**

asm("sub rsp, 0xe0nt" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] nt"
"push %[fn_str] nt"
"call nt"
"add rsp, 0xe0 + 3*8 nt" // pop red-zone skip space + pushed args

// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);


Notice that the output are not early-clobber, so the compiler can (at its option) use those registers for inputs, but we're not forcing it so the compiler is still free to use some other register or an immediate.



Upon further discussion, Go functions don't clobber RBP, so there's no reason to save/restore it manually. The only reason you might have wanted to is that locals might use RBP-relative addressing modes, and older GCC made it an error to declare a clobber on RBP when compiling without -fomit-frame-pointer. (I think. Or maybe I'm thinking of EBX in 32-bit PIC code.)





Also, if you're using the x86-64 System V ABI, beware that inline asm must not clobber the red-zone. The compiler assumes that doesn't happen and there's no way to declare a clobber on the red zone or even set -mno-redzone on a per-function basis. So you probably need to sub rsp, 128 + 0xe0. Or 0xe0 already includes enough space to skip the red-zone if that's not part of the callee's args.






share|improve this answer


























  • Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

    – reijin
    Nov 14 '18 at 0:10








  • 1





    @reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

    – Peter Cordes
    Nov 15 '18 at 12:50






  • 1





    @reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

    – Peter Cordes
    Nov 15 '18 at 14:29






  • 1





    @reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

    – Peter Cordes
    Nov 15 '18 at 14:32








  • 1





    @reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

    – Peter Cordes
    Nov 15 '18 at 14:39


















2














A "g" constraint allows the compiler to pick memory or register, so obviously you'll end up with mov mem,mem if that happens. mov can have at most 1 memory operand. (Like all x86 instructions, at most one explicit memory operand is possible.)



Use "ri" constraints for the inputs that will be moved to a memory destination, to allow register or immediate but not memory.



Also, you're modifying RSP so you can't safely use memory source operands. The compiler is going to assume it can use addressing modes like [rsp+16] or [rsp-4]. So you can't use push instead of mov.





You also need to declare clobbers on all the call-clobbered registers, because the function call will do that. (Or better, maybe ask for the inputs in those call-clobbered registers so the compiler doesn't have to bounce them through call-preserved regs like RBX. But you need to make those operands read/write or declare separate output operands for the same registers to let the compiler know they'll be modified.)



So probably your best bet for efficiency is something like



int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**

asm("sub rsp, 0xe0nt" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] nt"
"push %[fn_str] nt"
"call nt"
"add rsp, 0xe0 + 3*8 nt" // pop red-zone skip space + pushed args

// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);


Notice that the output are not early-clobber, so the compiler can (at its option) use those registers for inputs, but we're not forcing it so the compiler is still free to use some other register or an immediate.



Upon further discussion, Go functions don't clobber RBP, so there's no reason to save/restore it manually. The only reason you might have wanted to is that locals might use RBP-relative addressing modes, and older GCC made it an error to declare a clobber on RBP when compiling without -fomit-frame-pointer. (I think. Or maybe I'm thinking of EBX in 32-bit PIC code.)





Also, if you're using the x86-64 System V ABI, beware that inline asm must not clobber the red-zone. The compiler assumes that doesn't happen and there's no way to declare a clobber on the red zone or even set -mno-redzone on a per-function basis. So you probably need to sub rsp, 128 + 0xe0. Or 0xe0 already includes enough space to skip the red-zone if that's not part of the callee's args.






share|improve this answer


























  • Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

    – reijin
    Nov 14 '18 at 0:10








  • 1





    @reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

    – Peter Cordes
    Nov 15 '18 at 12:50






  • 1





    @reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

    – Peter Cordes
    Nov 15 '18 at 14:29






  • 1





    @reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

    – Peter Cordes
    Nov 15 '18 at 14:32








  • 1





    @reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

    – Peter Cordes
    Nov 15 '18 at 14:39
















2












2








2







A "g" constraint allows the compiler to pick memory or register, so obviously you'll end up with mov mem,mem if that happens. mov can have at most 1 memory operand. (Like all x86 instructions, at most one explicit memory operand is possible.)



Use "ri" constraints for the inputs that will be moved to a memory destination, to allow register or immediate but not memory.



Also, you're modifying RSP so you can't safely use memory source operands. The compiler is going to assume it can use addressing modes like [rsp+16] or [rsp-4]. So you can't use push instead of mov.





You also need to declare clobbers on all the call-clobbered registers, because the function call will do that. (Or better, maybe ask for the inputs in those call-clobbered registers so the compiler doesn't have to bounce them through call-preserved regs like RBX. But you need to make those operands read/write or declare separate output operands for the same registers to let the compiler know they'll be modified.)



So probably your best bet for efficiency is something like



int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**

asm("sub rsp, 0xe0nt" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] nt"
"push %[fn_str] nt"
"call nt"
"add rsp, 0xe0 + 3*8 nt" // pop red-zone skip space + pushed args

// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);


Notice that the output are not early-clobber, so the compiler can (at its option) use those registers for inputs, but we're not forcing it so the compiler is still free to use some other register or an immediate.



Upon further discussion, Go functions don't clobber RBP, so there's no reason to save/restore it manually. The only reason you might have wanted to is that locals might use RBP-relative addressing modes, and older GCC made it an error to declare a clobber on RBP when compiling without -fomit-frame-pointer. (I think. Or maybe I'm thinking of EBX in 32-bit PIC code.)





Also, if you're using the x86-64 System V ABI, beware that inline asm must not clobber the red-zone. The compiler assumes that doesn't happen and there's no way to declare a clobber on the red zone or even set -mno-redzone on a per-function basis. So you probably need to sub rsp, 128 + 0xe0. Or 0xe0 already includes enough space to skip the red-zone if that's not part of the callee's args.






share|improve this answer















A "g" constraint allows the compiler to pick memory or register, so obviously you'll end up with mov mem,mem if that happens. mov can have at most 1 memory operand. (Like all x86 instructions, at most one explicit memory operand is possible.)



Use "ri" constraints for the inputs that will be moved to a memory destination, to allow register or immediate but not memory.



Also, you're modifying RSP so you can't safely use memory source operands. The compiler is going to assume it can use addressing modes like [rsp+16] or [rsp-4]. So you can't use push instead of mov.





You also need to declare clobbers on all the call-clobbered registers, because the function call will do that. (Or better, maybe ask for the inputs in those call-clobbered registers so the compiler doesn't have to bounce them through call-preserved regs like RBX. But you need to make those operands read/write or declare separate output operands for the same registers to let the compiler know they'll be modified.)



So probably your best bet for efficiency is something like



int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**

asm("sub rsp, 0xe0nt" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] nt"
"push %[fn_str] nt"
"call nt"
"add rsp, 0xe0 + 3*8 nt" // pop red-zone skip space + pushed args

// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);


Notice that the output are not early-clobber, so the compiler can (at its option) use those registers for inputs, but we're not forcing it so the compiler is still free to use some other register or an immediate.



Upon further discussion, Go functions don't clobber RBP, so there's no reason to save/restore it manually. The only reason you might have wanted to is that locals might use RBP-relative addressing modes, and older GCC made it an error to declare a clobber on RBP when compiling without -fomit-frame-pointer. (I think. Or maybe I'm thinking of EBX in 32-bit PIC code.)





Also, if you're using the x86-64 System V ABI, beware that inline asm must not clobber the red-zone. The compiler assumes that doesn't happen and there's no way to declare a clobber on the red zone or even set -mno-redzone on a per-function basis. So you probably need to sub rsp, 128 + 0xe0. Or 0xe0 already includes enough space to skip the red-zone if that's not part of the callee's args.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 15 '18 at 14:43

























answered Nov 13 '18 at 18:21









Peter CordesPeter Cordes

122k17184312




122k17184312













  • Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

    – reijin
    Nov 14 '18 at 0:10








  • 1





    @reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

    – Peter Cordes
    Nov 15 '18 at 12:50






  • 1





    @reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

    – Peter Cordes
    Nov 15 '18 at 14:29






  • 1





    @reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

    – Peter Cordes
    Nov 15 '18 at 14:32








  • 1





    @reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

    – Peter Cordes
    Nov 15 '18 at 14:39





















  • Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

    – reijin
    Nov 14 '18 at 0:10








  • 1





    @reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

    – Peter Cordes
    Nov 15 '18 at 12:50






  • 1





    @reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

    – Peter Cordes
    Nov 15 '18 at 14:29






  • 1





    @reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

    – Peter Cordes
    Nov 15 '18 at 14:32








  • 1





    @reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

    – Peter Cordes
    Nov 15 '18 at 14:39



















Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

– reijin
Nov 14 '18 at 0:10







Dude, you are a lifesaver! I learn so much from your responses. Thanks again! edit: will accept once I tested it tomorrow. Not sure if my way of calling the function is the best way, but I'm trying to emulate what Golang does when calling a function.

– reijin
Nov 14 '18 at 0:10






1




1





@reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

– Peter Cordes
Nov 15 '18 at 12:50





@reijin: updated with an example of clobbers + register inputs that should allow inputs to be in call-clobbered registers, at the compiler's option.

– Peter Cordes
Nov 15 '18 at 12:50




1




1





@reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

– Peter Cordes
Nov 15 '18 at 14:29





@reijin: I don't know what registers Go treats as call-clobbered, but I just updated my answer with the complete set of call-clobbered x86-64 System V registers.

– Peter Cordes
Nov 15 '18 at 14:29




1




1





@reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

– Peter Cordes
Nov 15 '18 at 14:32







@reijin: Are you sure Go doesn't restore the caller's RBP before returning? Part of making a traditional stack frame is saving the caller's RBP so you can restore it with leave or pop rbp.

– Peter Cordes
Nov 15 '18 at 14:32






1




1





@reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

– Peter Cordes
Nov 15 '18 at 14:39







@reijin: Then there's no reason to save/restore rbp inside your inline asm. It's just like RBX or R15 as far as the compiler is concerned.

– Peter Cordes
Nov 15 '18 at 14:39















0














The original poster added this solution as an edit to their question:



If someone ever finds this, the accepted answer does not help you when you try to call golang code with inline asm! The accepted answer only helps with my initial problem, which helped me to fix the golangcall. Use something like this:**



void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; tn
mov [rsp], %[p1]; tn
mov [rsp+0x8], %[p2]; tn
mov [rsp+0x10], %[p3]; tn
mov [rsp+0x18], %[p4]; tn
call %[func_addr]; tn
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}





share|improve this answer





















  • 1





    This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

    – Peter Cordes
    Nov 21 '18 at 23:01













  • @PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

    – Michael Petch
    Nov 22 '18 at 0:01













  • @PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

    – reijin
    Nov 22 '18 at 17:00













  • @reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

    – Peter Cordes
    Nov 22 '18 at 17:55








  • 2





    @reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

    – Peter Cordes
    Nov 22 '18 at 17:58
















0














The original poster added this solution as an edit to their question:



If someone ever finds this, the accepted answer does not help you when you try to call golang code with inline asm! The accepted answer only helps with my initial problem, which helped me to fix the golangcall. Use something like this:**



void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; tn
mov [rsp], %[p1]; tn
mov [rsp+0x8], %[p2]; tn
mov [rsp+0x10], %[p3]; tn
mov [rsp+0x18], %[p4]; tn
call %[func_addr]; tn
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}





share|improve this answer





















  • 1





    This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

    – Peter Cordes
    Nov 21 '18 at 23:01













  • @PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

    – Michael Petch
    Nov 22 '18 at 0:01













  • @PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

    – reijin
    Nov 22 '18 at 17:00













  • @reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

    – Peter Cordes
    Nov 22 '18 at 17:55








  • 2





    @reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

    – Peter Cordes
    Nov 22 '18 at 17:58














0












0








0







The original poster added this solution as an edit to their question:



If someone ever finds this, the accepted answer does not help you when you try to call golang code with inline asm! The accepted answer only helps with my initial problem, which helped me to fix the golangcall. Use something like this:**



void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; tn
mov [rsp], %[p1]; tn
mov [rsp+0x8], %[p2]; tn
mov [rsp+0x10], %[p3]; tn
mov [rsp+0x18], %[p4]; tn
call %[func_addr]; tn
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}





share|improve this answer















The original poster added this solution as an edit to their question:



If someone ever finds this, the accepted answer does not help you when you try to call golang code with inline asm! The accepted answer only helps with my initial problem, which helped me to fix the golangcall. Use something like this:**



void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; tn
mov [rsp], %[p1]; tn
mov [rsp+0x8], %[p2]; tn
mov [rsp+0x10], %[p3]; tn
mov [rsp+0x18], %[p4]; tn
call %[func_addr]; tn
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}






share|improve this answer














share|improve this answer



share|improve this answer








answered Nov 21 '18 at 22:26


























community wiki





Michael Petch









  • 1





    This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

    – Peter Cordes
    Nov 21 '18 at 23:01













  • @PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

    – Michael Petch
    Nov 22 '18 at 0:01













  • @PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

    – reijin
    Nov 22 '18 at 17:00













  • @reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

    – Peter Cordes
    Nov 22 '18 at 17:55








  • 2





    @reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

    – Peter Cordes
    Nov 22 '18 at 17:58














  • 1





    This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

    – Peter Cordes
    Nov 21 '18 at 23:01













  • @PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

    – Michael Petch
    Nov 22 '18 at 0:01













  • @PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

    – reijin
    Nov 22 '18 at 17:00













  • @reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

    – Peter Cordes
    Nov 22 '18 at 17:55








  • 2





    @reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

    – Peter Cordes
    Nov 22 '18 at 17:58








1




1





This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

– Peter Cordes
Nov 21 '18 at 23:01







This "answer" has multiple bugs that I warned about in my answer: you don't tell the compiler about the call-clobbered registers, and you step on the red-zone because you don't sub enough stack space to go past it. sub rsp, 0x80 / 4x push / call / add rsp, 0x80 + 4*8 should do the trick, along with clobbers as shown in my answer. There's no need to use mov to put args on the stack, push works perfectly fine. (@michael: I know this will ping you, but I'm posting for the benefit of future readers.)

– Peter Cordes
Nov 21 '18 at 23:01















@PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

– Michael Petch
Nov 22 '18 at 0:01







@PeterCordes :Understood. For other readers - my intent of posting this was to capture the OP's late edit, and I was taking no technical responsibility for it ;-). It was marked a community Wiki as I felt it was probably at least reasonable to move his update to an answer whether it be a good or bad answer. What I forgot to do was remove his solution from the question.Oops.

– Michael Petch
Nov 22 '18 at 0:01















@PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

– reijin
Nov 22 '18 at 17:00







@PeterCordes: Okok, I get it. I prefer the mov way, as it doesn't force me to do the additional sub call. But I guess it's clearer to use push. Regarding your point on redzone and clubbered registers: I'm aware of it, it's just that I didn't run into any errors (yet), so this works fine for now. Your answer is still the better and more fleshed-out one!

– reijin
Nov 22 '18 at 17:00















@reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

– Peter Cordes
Nov 22 '18 at 17:55







@reijin: If you ignore the red-zone, it's mov that needs a sub rsp, offset. With push you can just start pushing to move RSP for free. But since you need to skip over the red-zone, both ways need one sub and one add. The only advantage to mov is that you can see explicitly which offset you're storing what, instead of having to push in reverse order of args. (right-most arg first, so it's at the highest address).

– Peter Cordes
Nov 22 '18 at 17:55






2




2





@reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

– Peter Cordes
Nov 22 '18 at 17:58





@reijin: it's common to write inline asm that happens to work in one test, but is actually broken and will cause hard-to-debug problems down the road after changes to some unrelated code. Or just with a new compiler version and/or build options (especially link-time optimization enabling inlining across source files.)

– Peter Cordes
Nov 22 '18 at 17:58


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287194%2ftoo-many-memory-references-for-mov-when-calling-a-golang-function-with-c-by-us%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

List item for chat from Array inside array React Native

Thiostrepton

Caerphilly