I am currently following an introductory course in microelectronics and assembly programming in Uni. At the beginning of every function, I'm saving the caller's base pointer by pushing it onto the stack. Given the following function, I get an error:
.globl my_func
.globl _my_func
my_func:
_my_func:
pushl %ebp
movl %esp,%ebp
movl 4(%esp),%ebx
subl $1,%ebx
movl %ebx,%eax
ret
0xbffff8a8: aam $-0x8 <-EXC_BAD_ACCESS (code=2, address=0xbffff8a8)
I've figured out this is a memory exception, I just don't understand why it's being thrown. When I skip the first two instructions in the function (the base pointer saving), the function runs well. And before you point it out -- yes, I know the function is pointless and slow, I'm just trying to learn how the instructions work, and how to use the stack and registers.
I'm assembling it for IA32 on an Intel Mac with OSX10.9 using LLVM5.1
You need to reset the stack pointer at the end of the function, either explicitly or by popping a register to match what you pushed at the start of the function, otherwise when you return it will be to an invalid address:
popl %ebp ; restore stack pointer to its original value
ret
Related
Recently I just begin to read the source code of atomic.LoadUint64, then I got an unknown variable "ptr" in the following asm code:
TEXT runtime∕internal∕atomic·Load64(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
MOVL 0, AX // crash with nil ptr deref
MOVQ (AX), M0
MOVQ M0, ret+4(FP)
EMMS
RET
I couldn't find the declaration of this variable, and any documents about this variable, can anyone tell me about it?
A Quick Guide to Go's Assembler
Symbols
The FP pseudo-register is a virtual frame pointer used to refer to
function arguments. The compilers maintain a virtual frame pointer and
refer to the arguments on the stack as offsets from that
pseudo-register. Thus 0(FP) is the first argument to the function,
8(FP) is the second (on a 64-bit machine), and so on. However, when
referring to a function argument this way, it is necessary to place a
name at the beginning, as in first_arg+0(FP) and second_arg+8(FP).
(The meaning of the offset—offset from the frame pointer—distinct from
its use with SB, where it is an offset from the symbol.) The
assembler enforces this convention, rejecting plain 0(FP) and
8(FP). The actual name is semantically irrelevant but should be used
to document the argument's name. It is worth stressing that FP is
always a pseudo-register, not a hardware register, even on
architectures with a hardware frame pointer.
ptr, in ptr+0(FP), is a name for the first argument to the function. The argument is probably a pointer.
I am trying to learn writing assembly language for 64 bit Mac OS. I have no problem with 32 bit Mac OS and both 32 bit and 64 bit Linux.
However, Mac OS 64 bit is different and I couldn't figure out. Therefore I am here to ask for help.
I have not problem using system call to print. However, I would like to learn how to call C functions using 64 bit assembly language of Mac OS.
Please look at the following code
.data
_hello:
.asciz "Hello, world\n"
.text
.globl _main
_main:
movq $0, %rax
movq _hello(%rip), %rdi
call _printf
I use
$ gcc -arch x86_64 hello.s
to assemble and link.
It generates binary code. However, I got a segmentation fault when running it.
I tried adding "subq $8, %rsp" before calling _printf, still the same result as before.
What did I do wrong?
By the way, is that any way to debug this code on Mac? I tried adding -ggdb or -gstab or -gDWARF, and
$gdb ./a.out, and can't see the code and set break points.
You didn't say exactly what the problem you're seeing is, but I'm guessing that you're crashing at the point of the call to printf. This is because OS X (both 32- and 64-bit) requires that the stack pointer have 16-byte alignment at the point of any external function call.
The stack pointer was 16-byte aligned when _main was called; that call pushed an eight-byte return address onto the stack, so the stack is not 16-byte aligned at the point of the call to _printf. Subtract eight from %rsp before making the call in order to properly align it.
So I went ahead and debugged this for you (no magic involved, just use gdb, break main, display/5i $pc, stepi, etc). The other problem you're having is here:
movq _hello(%rip), %rdi
This loads the first eight bytes of your string into %rdi, which isn't what you want at all (in particular, the first eight bytes of your string are exceedingly unlikely to constitute a valid pointer to a format string, which results in a crash in printf). Instead, you want to load the address of the string. A debugged version of your program is:
.cstring
_hello: .asciz "Hello, world\n"
.text
.globl _main
_main:
sub $8, %rsp // align rsp to 16B boundary
mov $0, %rax
lea _hello(%rip), %rdi // load address of format string
call _printf // call printf
add $8, %rsp // restore rsp
ret
I'm using GCC with the -fomit-frame-pointer and -O2 options. When I looked through the assembly code it generated,
push %ebp
movl %esp, %ebp
at the start and pop %ebp at the end is removed. But some redundant subl/addl instructions to esp is left in - subl $12, %esp at the start and addl $12, %esp at the end.
How will I be able to remove them as some inline assembly will jmp to another function before addl is excecuted.
You probably don't want to remove those -- that's usually the code that allocates and deallocates your local variables. If you remove those, your code will trample all over the return addresses and such.
The only safe way to get rid of them is not to use any local variables. Even in macros. And be really careful about inline functions, as they often have their own locals that'll get put in with yours. You may want to consider explicitly disabling function inlining for that section of code, if you can.
If you're absolutely sure that the adds and subs aren't needed (and i mean really, really sure), on my machine GCC apaprently does some stack manipulation to keep the stack aligned at 16 byte boundaries. You may be able to say "-mpreferred-stack-boundary=2", which will align to 4-byte boundaries -- which x86 processors like to do anyway, so no code is generated to realign it. Works on my box with my GCC; int main() { return 0; } turned into
main:
xorl %eax, %eax
ret
but the alignment code looked different to start with...so that may not be the problem for you.
Just so you're warned: optimization causes a lot of weird stuff like that to happen. Be careful with hand-coded assembler language and optimized <insert-almost-any-language-here> code, especially when you're doing something as unstructured as a jump from the middle of one function into another.
I solved the problem by giving a function prototype, then defining it manually like this:
void my_function();
asm (
".globl _my_function\n"
"_my_function:\n\t"
/* Assembler instructions go here */
);
Later I also wanted the function to be exported, so I added this at the end of the source file:
asm (
".section .drectve\n\t"
".ascii \" -export:my_function\"\n"
);
How will I be able to remove them as some inline assembly will jmp to another function before addl is executed.
This will corrupt your stack, that caller expects the stack pointer
to be corrected on function return. Does the other function return
by ret instruction? What exactly do you try to achieve? maybe there's another solution possible?
Please, show us the lines around the function call (in the caller) and your
entry/exit part of your function in question.
What effect these two instructions cause in the assembly code generated by gcc for x86 machines:
push %ebp
movl %esp, %ebp
unwind's explanation is the literal truth (one minor directional error notwithstanding), but doesn't explain why.
%ebp is the "base pointer" for your stack frame. It's the pointer used by the C runtime to access local variables and parameters on the stack. Here's some typical function prologue code generated by GCC (g++ to be precise) First the C++ source.
// junk.c++
int addtwo(int a)
{
int x = 2;
return a + x;
}
This generates the following assembler.
.file "junk.c++"
.text
.globl _Z6addtwoi
.type _Z6addtwoi, #function
_Z6addtwoi:
.LFB2:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
subl $16, %esp
.LCFI2:
movl $2, -4(%ebp)
movl -4(%ebp), %edx
movl 8(%ebp), %eax
addl %edx, %eax
leave
ret
.LFE2:
.size _Z6addtwoi, .-_Z6addtwoi
.ident "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
.section .note.GNU-stack,"",#progbits
Now to explain that prologue code (all the stuff before .LCFI2:), first:
pushl %ebp stores the stack frame of the calling function on the stack.
movl %esp, %ebp takes the current stack pointer and uses it as the frame for the called function.
subl $16, %esp leaves room for local variables.
Now your function is ready for business. Any references with a negative offset from the %ebp% register are your local variables (x in this example). Any references with a positive offset from the %ebp% register are your parameters passed in.
The final point of interest is the leave instruction which is an x86 assembler instruction which does the work of restoring the calling function's stack frame. This is usually optimized away in to the faster move %ebp %esp and pop %ebp% sequence in C code. For illustrative purposes, however, I didn't compile with any optimizations on at all.
It's typical code that you see at the beginning of a function.
It saves the contents of the EBP register on the stack, and then stores the content of the current stack pointer in EBP.
The stack is used during a function call to store local arguments. But in the function, the stack pointer may change because values are stored on the stack.
If you save the original value of the stack, you can refer to the stored arguments via the EBP register, while you can still use (add values to) the stack.
At the end of the function you will probably see the command
pop %ebp ; restore original value
ret ; return
push %ebp
This will push the 32 bit (extended) base pointer register on the stack, i.e. the stack pointer (%esp) is subtracted by four, then the value of %ebp is copied to the location that the stack pointer points to.
movl %esp, %ebp
This copies the stack pointer register to the base pointer register.
The purpose of copying the stack pointer to the base pointer is to create a stack frame, i.e. an area on the stack where a subroutine can store local data. The code in the subroutine would use the base pointer to reference the data.
It's part of what is known as the function prolog.
It saves the current base pointer that is going to be retrieved when the function ends and sets the new ebp to the beginning of the new frame.
I also think that it is important to note that often after
push %ebp and
movl %esp, %ebp
the assembly will have push %ebx or push %edx. These are caller saves of the registers %ebx and %edx. At the end of the routine call the registers will be restored with their original values.
Also - %ebx, %esi, %edi are all callee save registers. So if you want to overwrite them you need to save them first, then restore them.
The piece of code sets up the stack for your program.
In x86 stack information is held by two registers.
Base pointer (bp): Holds starting address of the stack
Stack pointer (sp): Holds the address in which next value will be stored
These registers have different names in different modes:
Base pointer Stack pointer
16 bit real mode: bp sp
32 bit protected mode: ebp(%ebp) esp(%esp)
64 bit mode: rbp rsp
When you set up a stack, stack pointer and base pointer gets the same address at the beginning.
Now to explain your code,
push %ebp
This code pushes the current stack address into the stack so that the function can "exit" or "return" properly.
movl %esp, %ebp
This code sets up the stack for your function.
For more info, refer to this question.
Hope this help!
Treat this more as pseudocode than anything. If there's some macro or other element that you feel should be included, let me know.
I'm rather new to assembly. I programmed on a pic processor back in college, but nothing since.
The problem here (segmentation fault) is the first instruction after "Compile function entrance, setup stack frame." or "push %ebp". Here's what I found out about those two instructions:
http://unixwiz.net/techtips/win32-callconv-asm.html
Save and update the %ebp :
Now that we're in the new function, we need a new local stack frame pointed to by %ebp, so this is done by saving the current %ebp (which belongs to the previous function's frame) and making it point to the top of the stack.
push ebp
mov ebp, esp // ebp « esp
Once %ebp has been changed, it can now refer directly to the function's arguments as 8(%ebp), 12(%ebp). Note that 0(%ebp) is the old base pointer and 4(%ebp) is the old instruction pointer.
Here's the code. This is from a JIT compiler for a project I'm working on. I'm doing this more for the learning experience than anything.
IL_CORE_COMPILE(avs_x86_compiler_compile)
{
X86GlobalData *gd = X86_GLOBALDATA(ctx);
ILInstruction *insn;
avs_debug(print("X86: Compiling started..."));
/* Initialize X86 Assembler opcode context */
x86_context_init(&gd->ctx, 4096, 1024*1024);
/* Compile function entrance, setup stack frame*/
x86_emit1(&gd->ctx, pushl, ebp);
x86_emit2(&gd->ctx, movl, esp, ebp);
/* Setup floating point rounding mode to integer truncation */
x86_emit2(&gd->ctx, subl, imm(8), esp);
x86_emit1(&gd->ctx, fstcw, disp(0, esp));
x86_emit2(&gd->ctx, movl, disp(0, esp), eax);
x86_emit2(&gd->ctx, orl, imm(0xc00), eax);
x86_emit2(&gd->ctx, movl, eax, disp(4, esp));
x86_emit1(&gd->ctx, fldcw, disp(4, esp));
for (insn=avs_il_tree_base(tree); insn != NULL; insn = insn->next) {
avs_debug(print("X86: Compiling instruction: %p", insn));
compile_opcode(gd, obj, insn);
}
/* Restore floating point rounding mode */
x86_emit1(&gd->ctx, fldcw, disp(0, esp));
x86_emit2(&gd->ctx, addl, imm(8), esp);
/* Cleanup stack frame */
x86_emit0(&gd->ctx, emms);
x86_emit0(&gd->ctx, leave);
x86_emit0(&gd->ctx, ret);
/* Link machine */
obj->run = (AvsRunnableExecuteCall) gd->ctx.buf;
return 0;
}
And when obj->run is called, it's called with obj as its only argument:
obj->run(obj);
If it helps, here are the instructions for the entire function call. It's basically an assignment operation: foo=3*0.2;. foo is pointing to a float in C.
0x8067990: push %ebp
0x8067991: mov %esp,%ebp
0x8067993: sub $0x8,%esp
0x8067999: fnstcw (%esp)
0x806799c: mov (%esp),%eax
0x806799f: or $0xc00,%eax
0x80679a4: mov %eax,0x4(%esp)
0x80679a8: fldcw 0x4(%esp)
0x80679ac: flds 0x806793c
0x80679b2: fsts 0x805f014
0x80679b8: fstps 0x8067954
0x80679be: fldcw (%esp)
0x80679c1: add $0x8,%esp
0x80679c7: emms
0x80679c9: leave
0x80679ca: ret
Edit: Like I said above, in the first instruction in this function, %ebp is void. This is also the instruction that causes the segmentation fault. Is that because it's void, or am I looking for something else?
Edit: Scratch that. I keep typing edp instead of ebp. Here are the values of ebp and esp.
(gdb) print $esp
$1 = (void *) 0xbffff14c
(gdb) print $ebp
$3 = (void *) 0xbffff168
Edit: Those values above are wrong. I should have used the 'x' command, like below:
(gdb) x/x $ebp
0xbffff168: 0xbffff188
(gdb) x/x $esp
0xbffff14c: 0x0804e481
Here's a reply from someone on a mailing list regarding this. Anyone care to illuminate what he means a bit? How do I check to see how the stack is set up?
An immediate problem I see is that the
stack pointer is not properly aligned.
This is 32-bit code, and the Intel
manual says that the stack should be
aligned at 32-bit addresses. That is,
the least significant digit in esp
should be 0, 4, 8, or c.
I also note that the values in ebp and
esp are very far apart. Typically,
they contain similar values --
addresses somewhere in the stack.
I would look at how the stack was set
up in this program.
He replied with corrections to the above comments. He was unable to see any problems after further input.
Another edit: Someone replied that the code page may not be marked executable. How can I insure it is marked as such?
The problem had nothing to do with the code. Adding -z execstack to the linker fixed the problem.
If push %ebp is causing a segfault, then your stack pointer isn't pointing at valid stack. How does control reach that point? What platform are you on, and is there anything odd about the runtime environment? At the entry to the function, %esp should point to the return address in the caller on the stack. Does it?
Aside from that, the whole function is pretty weird. You go out of your way to set the rounding bits in the fp control word, and then don't perform any operations that are affected by rounding. All the function does is copy some data, but uses floating-point registers to do it when you could use the integer registers just as well. And then there's the spurious emms, which you need after using MMX instructions, not after doing x87 computations.
Edit See Scott's (the original questioner) answer for the actual reason for the crash.