Calling assembly code from C++

So I've been trying to figure out how I'd write a little function in assembly and then call it from C++, and so far I've been able to call the function and it does do something, but not exactly what I wanted. I'm trying to basically write a function in assembly to output to the terminal,but when I call it, I get this weird extra characters in front of the message that I passed, so I'm not sure but I think im assigning something wrong or something I'm really not sure. I tried looking up the calling conventions for C stuff, and I found this link: https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI which I assume is right since im on macos, but attempting to use RSI and RDI instead of the stack to get my arguments just made the write function do nothing at all, so I'm really not sure what im doing here...

my code looks like this:

try.s:
1
2
3
4
5
6
7
8
9
.globl _write
.text
_write:
  movq $0x2000004, %rax
  movq $1, %rdi
  movq -16(%rbp), %rdx
  movq -8(%rbp), %rsi
  syscall
  ret

write.cpp:
1
2
3
4
5
6
7
8
extern "C" void write(const char *buf, long long len);

int main() {
  // const char *msg = "hello world\n";
  // const int len = 14;
  // write(msg, len);
  write("hello world\n", 14);
}


and then i compile it with clang++ try.s write.cpp, and when running it I end up getting (very consistently)
1�]�hello world

so I don't know how but I'm somehow just not getting the pointer argument right I guess?? I'm really not sure.
Last edited on
oh I also forgot to mention that when I tried to use the commented out code you see above instead of just directly calling write("hello world\n", 14), nothing printed as well, just like when I tried to get the function arguments from RSI and RDI.
The first 2 args are passed in RDI and RSI and the stack (RBP) isn't used. So RDI will be buf and RSI will be len. What args does sycall for 0x2000004 expect?
so syscall 0x2000004 is the write syscall and expects %rdi to be the file descriptor, %rsi to be the buffer, and %rdx to be the number of bytes to write. that being said, after reading ur response I now realize that I was assigning to the %rdi register twice and overwriting the argument in the process... such a silly mistake. thanks for the confirmation on the ABI :)

new (working) code:
try.s:
1
2
3
4
5
6
7
8
9
10
11
.globl _write
.text
_write:
  movq $0x2000004, %rax
  movq %rsi, %rdx 
  # movq -16(%rbp), %rdx
  movq %rdi, %rsi 
  # movq -8(%rbp), %rsi
  movq $1, %rdi
  syscall
  ret

write.cpp:
1
2
3
4
5
6
7
8
extern "C" void write(const char *buf, long long len);

int main() {
  // const char *msg = "hello world\n";
  // const int len = 14;
  // write(msg, len);
  write("hello world\n", 14);
}
such a silly mistake


We've all been there, done that, got the teeshirt.......
True.. having the mistake hold me hostage until 6am in the morning is still wild tho lol.
Registered users can post here. Sign in or register to post.