I'm messing around with nasm, and after doing a hello world with no problem, I though I'd try to do some c integration.
I'm using c to open a file, and I then want to use the pointer returned for the open file to process the text. However, when I call fgetc with the pointer in rdi, I get a "no such file or directory", followed by a segfault.
What am I doing wrong?
int64_t asmFunc(FILE* a, char* b);
int main()
{
int num;
FILE *fptr;
size_t line_buf_size = 0;
char *ret = malloc(100);
fptr = fopen("./test.txt","r");
if(fptr == NULL)
{
printf("Error!");
exit(1);
}
printf("%ld", asmFunc(fptr, ret));
return 0;
}
global asmFunc
section .text
extern fgetc
asmFunc:
call fgetc ; segfault occurs here.
(...)
ret
The first instruction of asmFunc isn't a call either, but I removed some setup stuff for later operations to make it easier to read.
Well that just defeats the entire purpose of an MCVE. You need to re-run your test after simplifying to make sure it still shows the same problem as your full version. But for this answer, I'll assume your setup didn't clobber the fptr arg in RDI or modify RSP.
asmFunc:
call fgetc ; segfault occurs here.
fptr will still be in RDI, where your caller passed it, so that's correct for int fgetc(FILE *fp).
So presumably fgetc is segfaulting because you called it with a misaligned stack. (It was 16-byte aligned before the call that jumped to asmFunc, but you don't have an odd number of pushes or any sub rsp, 8*n). Modern builds of glibc actually do depend on 16-byte alignment for scanf (glibc scanf Segmentation faults when called from a function that doesn't align RSP) so it's easy to imagine that fgetc includes code that also compiles to include a movaps of something on the stack.
Once you fix this bug, you will have the problem that call fgetc destroys your char *ret arg, because your caller passes it in RSI. Arg-passing registers are call-clobbered. What registers are preserved through a linux x86-64 function call
asmFunc: ; (FILE *fptr, char *ret)
push rsi ; save ret
call fgetc
pop rsi
mov [rsi], al
ret
A C compiler would normally save/restore RBX and use mov to save ret there.
asmFunc: ; (FILE *fptr, char *ret)
push rbx
mov rbx, rsi ; save ret
call fgetc
mov [rbx], al
pop rbx ; restore rbx
ret
However, when I call fgetc with the pointer in rdi, I get a "no such file or directory", followed by a segfault.
No idea how you're getting "no such file or directory". Is that from your debugger looking source for glibc functions? If it's part of what your program itself prints, that makes near zero sense, because you do exit(1) correctly when fptr == NULL. And you don't use perror() or anything else that looks up errno codes to generate standard error strings.
You need to learn and follow the calling conventions documented in Linux x86-64 ABI specification, in particular its §3.2.3 Parameter passing section. So the pointer value fptr is in %rdi, and the pointer value ret is in %rsi and you probably should push a call frame for your asmFunc
Read also the x86 calling conventions wikipage.
If you are able to code the equivalent (even a simplified one) of asmFunc in C in some example.c file, I recommend compiling it with gcc -O -fverbose-asm -Wall -S example.c and looking into the emitted example.s assembler file for inspiration. Most of the time, the first machine instruction of such a function is not a call (but something, called the function prologue, changing the stack pointer %esp and allocating some call frame on the call stack)
For example, on my Linux/Debian/x86-64 with gcc-8
void asmfunc(FILE* fil, char*s) {
fputc ('\t', fil);
fputs (s, fil);
fputc ('\n', fil);
fflush (fil);
}
is compiled into:
.text
.globl asmfunc
.type asmfunc, #function
asmfunc:
.LFB11:
.cfi_startproc
pushq %rbp #
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
pushq %rbx #
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
subq $8, %rsp #,
.cfi_def_cfa_offset 32
movq %rdi, %rbx # fil, fil
movq %rsi, %rbp # s, s
# /tmp/example.c:4: fputc ('\t', fil);
movq %rdi, %rsi # fil,
movl $9, %edi #,
call fputc#PLT #
# /tmp/example.c:5: fputs (s, fil);
movq %rbx, %rsi # fil,
movq %rbp, %rdi # s,
call fputs#PLT #
# /tmp/example.c:6: fputc ('\n', fil);
movq %rbx, %rsi # fil,
movl $10, %edi #,
call fputc#PLT #
# /tmp/example.c:7: fflush (fil);
movq %rbx, %rdi # fil,
call fflush#PLT #
# /tmp/example.c:8: }
addq $8, %rsp #,
.cfi_def_cfa_offset 24
popq %rbx #
.cfi_def_cfa_offset 16
popq %rbp #
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE11:
.size asmfunc, .-asmfunc
.ident "GCC: (Debian 8.3.0-6) 8.3.0"
Notice however that in some cases, GCC is capable (e.g. with -O2) of tail-call optimizations and might call some leaf-functions specially.
Related
I am trying to learn how to use ptrace library for tracing all system calls and their arguments. I am stuck in getting the arguments passed to system call.
I went through many online resources and SO questions and figured out that on 64 bit machine the arguments are stored in registers rax(sys call number), rdi, rsi, rdx, r10, r8, r9
in the same order. Check this website .
Just to confirm this I wrote a simple C program as follows
#include<stdio.h>
#include<fcntl.h>
int main() {
printf("some print data");
open("/tmp/sprintf.c", O_RDWR);
}
and generated assembly code for this using gcc -S t.c but assembly code generated is as below
.file "t.c"
.section .rodata
.LC0:
.string "some print data"
.LC1:
.string "/tmp/sprintf.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $2, %esi
movl $.LC1, %edi
movl $0, %eax
call open
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",#progbits
As you can see this code is storing parameters on esi and edi instead.
Why is happening?
Also please guide me on what is the best way to access these passed arguments from these registers/memory location from a C code? How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
Thanks!
this code is storing parameters on esi and edi
32-bit instructions are smaller, thus preferred when possible. See also Why do most x64 instructions zero the upper part of a 32 bit register.
How can I figure out if the contents of register is the argument itself or is it a memory location where actual argument is stored?
The AMD64 SystemV calling convention never implicitly replaces a function arg with a hidden pointer. Integer / pointer args in the C prototype always go in the arg-passing registers directly.
structs / unions passed by value go in one or more registers, or on the stack.
The full details are documented in the ABI. See more links in the x86 tag wiki. http://www.x86-64.org/documentation.html is down right now, so I linked the current revision on github.
I was looking at the Compiler output for a C program, just for academic purposes and happened to get the following output.
.file "test.c"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",#progbits
I understand the parts where the based pointer and stack pointer operations are taking place and other operation, I wanted to know what is the use of putting
movl $.LC0, %edi
how is loading the address of the test "Hello world" from the data block into the destination register solving the purpose, we could have just loaded that address in the accumulator and let printf handle it. I am not used to programming in assembly but i can make out what the program is doing, am i missing something obvious here?
Google searches showed that they were used for string operations but none said why?
First of all, your call on printf may be passing arguments by registers and not by stack because it was optimised in that way, or because its attributes during compilation were set to __fastcall (MSVC) or __attribute__((fastcall)).
%esi and %esi registers are used in string operations because of their meaning to string instructions, such as cmps, lods, movs, scas, stos, outs or ins. These instructions use the destination and source register for quick sequential access to a string of bytes/words/doublewords. They can be used in loops to make simple operations that are known to be performed continuously in memory, and can shorter execution time in combination with loop prefixes by removing the need of pointer manipulation and limit checking.
A very good example on this is the movs instruction (it also has another forms as movsb, movsw, movsd). If you wanted to write a simple string copy procedure without string instruction, you write something like this:
; IN: EAX=source&, EBX=dest&, ECX=count
; OUT: nothing
copy:
.loop:
cmp ecx, 0
jz .end
dec ecx
mov al, byte [eax+ecx]
mov byte [ebx+ecx], al
jmp .loop
.end:
ret
movsb instruction copies [esi] to [edi], increments esi and edi, then decrements ecx. With this in mind you can write somethign similar to this:
; IN: ESI=source&, EDI=dest&, ECX=count
; OUT: nothing
copy:
.loop:
jecxz .end
movsb
jmp .loop
.end:
ret
Using loop prefixes, you can again speed the whole operation
; IN: ESI=source&, EDI=dest&, ECX=count
; OUT: nothing
copy:
rep movsb
ret
I am going to say yes and no to user35443 answer.
I wanted to know what is the use of putting
movl $.LC0, %edi
Since you are using 64bit Linux (from the use of rbp), in 64 bit land, parameters are passed in registers. rdi contains the first parameter, rsi the second, rdx 3rd, rcx 4th, r8 5th, r9 the 6th parameter; any more parameters are passed on the stack.
we could have just loaded that address in the accumulator and let
printf handle it
No! When using Assembly, it is up to you to read and understand the ABI for the OS you are using and follow it to the T! If you were using Windows, the first parameter would be in rcx instead. It has nothing to do with the source nor destination.
the "Accumulator" is actually a parameter to printf and all vararg functions really. r/eax contains the number of floating point numbers passed in the xmm registers, since in your example code no floats are passed, eax is set to 0.
Casually, when reading the assembler listing of a sample C program, I noted that the stack pointer is not 16 bit aligned before calling function foo:
void foo() { }
int func(int p) { foo(); return p; }
int main() { return func(1); }
func:
pushq %rbp
movq %rsp, %rbp
subq $8, %rsp ; See here
movl %edi, -4(%rbp)
movl $0, %eax
call foo
movl -4(%rbp), %eax
leave
ret
The subq $8, %rsp instruction makes RSP not aligned before calling foo (it should be "subq $16, %rsp").
In System V ABI, par. 3.2.2, I read: "the value (%rsp − 8) is always a multiple of 16 when control is transferred to the function entry point".
Someone can help me to understand why gcc doesn't put subq $16, %rsp ?
Thank you in advance.
Edit:
I forgot to mention my OS and compiler version:
Debian wheezy, gcc 4.7.2
Assuming that the stack pointer is 16-byte aligned when func is entered, then the combination of
pushq %rbp ; <- 8 bytes
movq %rsp, %rbp
subq $8, %rsp ; <- 8 bytes
will keep it 16-byte aligned for the subsequent call to foo().
It seems that since the compiler knows about the implementation of foo() and that it's a noop, it's not bothering with the stack alignment. If foo() is seen as only a declaration or prototype in the translation unit where func() is compiled you'll see your expected stack alignment.
I've been playing around with the asm macro in C to directly call some assembly instructions on OS X Mavericks to get a stack pointer address (from %rsp) and I've found really strange behaviour (at least to me) while trying to assign a return value from the assembler code into the %rax register (the one that should by convention hold the function return value). The C code is very simple:
#include <stdio.h>
unsigned long long get_sp(void) {
asm ("mov %rsp, %rax");
return 0;
}
int main(void) {
printf("0x%llx\n", get_sp());
}
If I compile and run the code, the value from %rax register gets printed(the actual stack pointer), which is strange as I would expect the %rax register to be overwritten by "return 0;"
However if I remove the return 0; a string "0x0" gets printed which is also strange as I would expect the return value from %rax register to be read and printed.
I've tried to run this code(with the only difference using %esp and %eax registers) also on the Ubuntu Linux also and it actually works as I would expect(using the gcc compiler).
Could this be a bug in the llvm-gcc compiler(Apple LLVM version 5.1)?
//EDIT
This is the version without the "return 0;"
otool -tV sp.out
sp.out:
(__TEXT,__text) section
_get_sp:
0000000100000f30 pushq %rbp
0000000100000f31 movq %rsp, %rbp
0000000100000f34 movq %rsp, %rax
0000000100000f37 movq -0x8(%rbp), %rax
0000000100000f3b popq %rbp
0000000100000f3c ret
0000000100000f3d nopl (%rax)
_main:
0000000100000f40 pushq %rbp
0000000100000f41 movq %rsp, %rbp
0000000100000f44 subq $0x10, %rsp
0000000100000f48 callq _get_sp
0000000100000f4d leaq 0x3a(%rip), %rdi ## literal pool for: "0x%llx
"
0000000100000f54 movq %rax, %rsi
0000000100000f57 movb $0x0, %al
0000000100000f59 callq 0x100000f6e ## symbol stub for: _printf
0000000100000f5e movl $0x0, %ecx
0000000100000f63 movl %eax, -0x4(%rbp)
0000000100000f66 movl %ecx, %eax
0000000100000f68 addq $0x10, %rsp
0000000100000f6c popq %rbp
0000000100000f6d ret
This is not a bug. It's the result of incorrect use of inline assembly. In the case where the return statement is included, the compiler does not inspect the asm statement. If %rax has already been set to zero before the asm block, the instruction overwrites that value. The compiler is free to do this before the asm block, since you haven't informed it of any register outputs, clobbers, etc.
In the case where no return statement is included, you can't rely on the return value. Which is why clang (that's what llvm-gcc is with Xcode 5.1 - it's not the gcc front end) issues a warning. gcc-4.8.2 appears to work on OS X - but because the code is incorrect in both cases, it's just 'luck'. With optimization: -O2, it no longer works. gcc doesn't issue a warning by default, which is a good reason to at least use -Wall.
{
unsigned long long ret;
__asm__ ("movq %rsp, %0" : "=r" (ret));
return ret;
}
always works. volatile is not necessary, as the compiler is using an output, so it cannot discard the asm statement. Even changing the first line to unsigned long long ret = 0; - the compiler is obviously not free to reorder.
this works for me on Mavericks [edit: and without a single change on Ubuntu Saucy x86_64]:
#include <stdio.h>
unsigned long long get_sp(void) {
long _sp = 0x0L;
__asm__ __volatile__(
"mov %%rsp, %[value] \n\t"
: [value] "=r" (_sp)
:
:);
return _sp;
}
int main(void) {
printf("0x%llx\n", get_sp());
}
I'm studying NASM on Linux 64-bit and have been trying to implement some examples of code. However I got a problem in the following example. The function donothing is implemented in NASM and is supposed to be called in a program implemented in C:
File main.c:
#include <stdio.h>
#include <stdlib.h>
int donothing(int, int);
int main() {
printf(" == %d\n", donothing(1, 2));
return 0;
}
File first.asm
global donothing
section .text
donothing:
push rbp
mov rbp, rsp
mov eax, [rbp-0x4]
pop rbp
ret
What donothing does is nothing more than returning the value of the first parameter. But when donothing is called the value 0 is printed instead of 1. I tried rbp+0x4, but it doesn't work too.
I compile the files using the following command:
nasm -f elf64 first.asm && gcc first.o main.c
Compiling the function 'test' in C by using gcc -s the assembly code generated to get the parameters looks similar to the donothing:
int test(int a, int b) {
return a > b;
}
Assembly generated by gcc for the function 'test' above:
test:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
cmpl -8(%rbp), %eax
setg %al
movzbl %al, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
So, what's wrong with donothing?
In x86-64 calling conventions the first few parameters are passed in registers rather than on the stack. In your case you should find the 1 and 2 in RDI and RSI.
As you can see in the compiled C code, it takes a from edi and b from esi (although it goes through an unnecessary intermediate step by placing them in memory)