I'm using a MacBook Pro with an Intel Core 2 Duo processor at 2.53 GHz, but I was told Mac users must follow AT&T syntax (which adds to my confusion since I am running Intel) and x86 (not sure what this means exactly).
So I need to get into assembly but am finding it very hard to even begin. Searches online show assembly code that varies greatly in syntax and I can't find any resources that explain basic assembly how-tos. I keep reading about registers and a stack but don't understand how to look at this. Can anyone explain/point me in the right direction? Take, for example, this code which is the only code I found to work:
.data
_mystring: .ascii "Hello World\n\0" #C expects strings to terminate with a 0.
.text
.globl _foo
_foo:
push %ebp
mov %esp,%ebp
pushl $_mystring
call _myprint
add $4,%esp
pop %ebp
ret
Very simple but what is it saying? I am having a confusing time understanding how this code does what it does. I know Java, PHP, and C, among other languages, but this, the steps and syntax of it, isn't clear to me. Here's the main file to go with it:
#include <stdio.h>
void foo();
void myprint(char *s)
{printf("%s", s);}
main()
{foo();}
Also, there's this which just multiplies numbers:
.data
.globl _cntr
_cntr: .long 0
.globl _prod
_prod: .long 0
.globl _x
_x: .long 0
.globl _y
_y: .long 0
.globl _mask
_mask: .long 1
.globl _multiply
multiply:
push %ebp
mov %ebp,%esp
mov $0,%eax
mov _x,%ebx
mov _y,%edx
LOOP:
cmp $0,%ebx
je DONE
mov %ebx,%ecx
and $1,%ecx
cmp $1,%ecx
jne LOOPC
add %edx,%eax
LOOPC:
shr $1,%ebx
shl $1,%edx
jmp LOOP
DONE:
pop %ebp
ret
and the main.c to go with it:
#include <stdio.h>
extern int multiply();
extern int x, y;
int main()
{
x = 34;
y = 47;
printf("%d * %d = %d\n", x, y, multiply());
}
And finally three small questions:
What is the difference between .s and .h file names (I have both a main.c and main.h, which one is for what)?
And why does assembly need a main.c to go with it/how does it call it?
Can anyone recommend a good assembly IDE like Eclipse is for Java or PHP
Thanks to whomever answers (this is actually my first post on this site), I've been trying to figure this out for a few days and every resource I have read just doesn't explain the assembly logic to me. It says what .data or .text does but only someone who knows how to "think assembly" would understand what they mean?
Also, if anyone is around New York City and feels very comfortable with Assembly and C I would love some private lessons. I feel there is a lot of potential with this language and would love to learn it.
Assembly language is a category of programming languages which are closely tied to CPU architectures. Traditionally, there is a one-to-one correspondence between each assembly instruction and the resulting CPU instruction.
There are also assembly pseudo-instructions which do not correspond to CPU instruction, but instead affect the assembler or the generated code. .data and .text are pseudo-instructions.
Historically, each CPU manufacturer implemented an assembly language as defined by their assembler, a source code translation utility. There have been thousands of specific assembly languages defined.
In modern times, it has been recognized that each assembly language shares a lot of common features, particularly with respect to pseudo-instructions. The GNU compiler collection (GCC) supports essentially every CPU architecture, so it has evolved generic assembly features.
x86 refers to the Intel 8086 family (8088, 8086, 8087, 80186, 80286, 80386, 80486, 80586 aka Pentium, 80686 aka Pentium II, etc.)
AT&T syntax is a notation style used by many assembly language architectures. A major feature is that instruction operands are written in the order from, to as was common historically. Intel syntax uses to, from operands. There are other differences as well.
As for your many questions, here are some resources which will 1) overwhelm you, and 2) eventually provide all your answers:
assembly language overview
tutorials and resources
x86 instruction summary
comprehensive x86 architecture reference
Ordinarily, an introductory assembly language programming class is a full semester with plenty of hands-on work. It assumes you are familiar with the basics of computer architecture. It is reasonable to expect that understanding the above material will take 300-500 hours. Good luck!
Related
I'm a total beginner at Assembly and i have been trying to get the basics in NASM. Im on a mac, using xcode and i have started dealing with data and i have a simple question.
I have had a hard time finding the answer and the manual for NASM is very overwhelming.
This must be super basic for you NASM guru's out there.
if i declare a variable out in memory
section .data
counter dw 0
global _start
_start:
inc counter ; i get a "invalid combination of opcode and operands" here
ret
Is it so that i must move the memory into a register to perform operations on it, and i can't manipulate memory "in place"?
Im sorry if this is a silly question, but i have tried googling this and couldn't find a clear straight up answer.
In NASM (unlike MASM) a bare symbol is an immediate value. For a memory reference enclose it in square brackets and indicate the required size.
inc word [counter]
I am trying to learn assembly language by example, or compiling simple C files with GCC using the -S option, intel syntax, and CFI calls disabled (every other free way is extremely confusing
My C file is literally just int main() {return 0;}, but GCC spits out this:
.file "simpleCTest.c"
.intel_syntax noprefix
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
push ebp
mov ebp, esp
and esp, -16
call ___main
mov eax, 0
leave
ret
.ident "GCC: (GNU) 5.3.0"
My real question is why does the main function have any processor instructions (push edp, mov edp, esp, etc)? Are these even necessary (I guess it would be a way of data management to prepare/shut down programs, but I'm not sure)? Why doesn't it just issue a ret statement after the main function? Also why are there TWO main functions (_main & ___main)?
To sum it up, why is it not just like this?
.def _main
_main:
mov eax, 0 ;(for return integer)
ret
GCC spits out this
This would probably be a bit clearer if you actually had your main function do some things, oddly enough, including calling another function.
Your compiled code is setting up a frame by which to reference its stack variables with the first opcode, mov ebp,esp. This would be used if you had variables that could be referred to with ebp and a constant, for instance. Then, it is aligning the stack to a multiple of 16 bytes with the AND instruction- that is, it is saying it will not use from 0 to 15 bytes of the provided stack, such that [esp] is aligned to a multiple of 16 bytes. This would be important because of the calling conventions in use.
The ending opcode leave copies the backed up base pointer over the current state of the stack pointer, and then restores the original base pointer with pop.
My real question is why does the main function have any processor instructions
It's setting stuff up for things that you aren't doing (but that nontrivial programs would do), and is not making the most optimized "return 0" program that it could. By having a base pointer that is mostly a backup of the original stack pointer, the program is free to refer to local variables as an offset plus the base pointer (including implied stuff you aren't using like the argument count, the pointer to the pointers to argument listing, and the pointer to the environment), and by having a stack pointer that is a multiple of 16, the program is free to make calls to functions according to its calling standard.
I am working on a nice tool, which requires the atomic swap of two different 64-bit values. On the amd64 architecture it is possible with the XCHGQ instruction (see here in doc, warning: it is a long pdf).
Correspondingly, gcc has some atomic builtins which would ideally do the same, as it is visible for example here.
Using these 2 docs I produced the following simple C function, for the atomic swapping of two, 64-bit values:
void theExchange(u64* a, u64* b) {
__atomic_exchange(a, b, b, __ATOMIC_SEQ_CST);
};
(Btw, it wasn't really clear to me, why needs an "atomic exchange" 3 operands.)
It was to me a little bit fishy, that the gcc __atomic_exchange macro uses 3 operands, so I tested its asm output. I compiled this with a gcc -O6 -masm=intel -S and I've got the following output:
.LHOTB0:
.p2align 4,,15
.globl theExchange
.type theExchange, #function
theExchange:
.LFB16:
.cfi_startproc
mov rax, QWORD PTR [rsi]
xchg rax, QWORD PTR [rdi] /* WTF? */
mov QWORD PTR [rsi], rax
ret
.cfi_endproc
.LFE16:
.size theExchange, .-theExchange
.section .text.unlikely
As we can see, the result function contains not only a single data move, but three different data movements. Thus, as I understood this asm code, this function won't be really atomic.
How is it possible? Maybe I misunderstood some of the docs? I admit, the gcc builtin doc wasn't really clear to me.
This is the generic version of __atomic_exchange_n (type *ptr, type val, int memorder) where only the exchange operation on ptr is atomic, the reading of val is not. In the generic version, val is accessed via pointer, but the atomicity still does not apply to it. The pointer is so that it will work with multiple sizes, when the compiler has to call an external helper:
The four non-arithmetic functions (load, store, exchange, and
compare_exchange) all have a generic version as well. This generic
version works on any data type. It uses the lock-free built-in
function if the specific data type size makes that possible;
otherwise, an external call is left to be resolved at run time. This
external call is the same format with the addition of a ‘size_t’
parameter inserted as the first parameter indicating the size of the
object being pointed to. All objects must be the same size.
I have been looking all over the Internet for an answer to this question (see subject of post). I have been asked this exact question twice. Once at an interview for company and once by a friend and I cannot find the answer for the life of me.
I have actually experienced this error on multiple occasions when debugging without a debugger, and just using print statements to isolate the error. I cannot recall any exact situations, though I am positive I have experienced it. If anyone can provide a link or a reference or point me to something in printf() source that might cause an error to stop occurring when using print statements to debug code I would greatly appreciate the good read.
Thank you,
Matthew Hoggan
I am currently reading the link provided but for further conversation I have posted some of my weak attempts to investigate:
Okay, so i have started to play around myself to try and answer my own question but things are still not 100% clear to me. Below is the output from the g++ compiler using the -S option to output the assembly instead of the executable. The equivalent C++ code is also posted below. My goal is to try and recreate a simple scenario and then try and detect based on the instructions what might be happening at the processor levels. So lets say right after the "call printf" assembly code, which I am assuming is linked from the library files stored in /usr/lib or another lib directory, I tried to access a NULL pointer (not in code), or some other form of operation that would traditionally crash the program. I am assuming that I would have to find out what printf is doing instruction wise to get a deeper look into this?
.file "assembly_test_printf.cpp"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
movl $0, 28(%esp)
movl $.LC0, (%esp)
call printf
movl 28(%esp), %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",#progbits
Equivalent C++ code:
#include <stdio.h>
int main ( int argc, char** argv ) {
int x = 0;
printf ("Hello World");
return x;
}
There are several reasons adding a printf() can change the behavior of a bug. Some of the more common ones might be:
changing the timing of execution (particularly for threading bugs)
changing memory use patterns (the compiler might change how the stack is used)
changing how registers are used
For example, an uninitialized local variable might be allocated to a register. Before adding the printf() the uninitialized variable is used and gets come garbage value that's in the register (maybe the result of a previous call to rand(), so it really is indeterminate). Adding the printf() causes the register to be used in printf() and printf() always happens to leave that register set to 0 (or whatever). Now your buggy program is still bugy, but with different behavior. And maybe that behavior happens to be benign.
I've seen it before, for example in Java, in cases where initialization code isn't complete when another thread attempts to access an object assumed to have already been created. The System.out.println() slows down the other thread enough for the initialization to complete.
I have a program written in assembly that crashes with a segmentation fault. (The code is irrelevant, but is here.)
My question is how to debug an assembly language program with GDB?
When I try running it in GDB and perform a backtrace, I get no meaningful information. (Just hex offsets.)
How can I debug the program?
(I'm using NASM on Ubuntu, by the way if that somehow helps.)
I would just load it directly into gdb and step through it instruction by instruction, monitoring all registers and memory contents as you go.
I'm sure I'm not telling you anything you don't know there but the program seems simple enough to warrant this sort of approach. I would leave fancy debugging tricks like backtracking (and even breakpoints) for more complex code.
As to the specific problem (code paraphrased below):
extern printf
SECTION .data
format: db "%d",0
SECTION .bss
v_0: resb 4
SECTION .text
global main
main:
push 5
pop eax
mov [v_0], eax
mov eax, v_0
push eax
call printf
You appear to be just pushing 5 on to the stack followed by the address of that 5 in memory (v_0). I'm pretty certain you're going to need to push the address of the format string at some point if you want to call printf. It's not going to take to kindly to being given a rogue format string.
It's likely that your:
mov eax, v_0
should be:
mov eax, format
and I'm assuming that there's more code after that call to printf that you just left off as unimportant (otherwise you'll be going off to never-never land when it returns).
You should still be able to assemble with Stabs markers when linking code (with gcc).
I reccomend using YASM and assembling with -dstabs options:
$ yasm -felf64 -mamd64 -dstabs file.asm
This is how I assemble my assembly programs.
NASM and YASM code is interchangable for the most part (YASM has some extensions that aren't available in NASM, but every NASM code is well assembled with YASM).
I use gcc to link my assembled object files together or while compiling with C or C++ code. When using gcc, I use -gstabs+ to compile it with debug markers.