Why cmp 2, 2 is't equal 0 - linux

extern putchar
extern exit
section .data
section .text
global main
main:
push 's'
mov eax, 2
cmp eax, 2
point:
call putchar
jz point
push 0
call exit
On the console I see only one 's' charcter.
Compile and run:
nasm -f elf ./prog.asm
gcc -m32 -o prog ./prog.o
./prog

The cmp is "equal to 0" (that is, it does set the ZF flag). However, the call putchar in the next line is trashing the flags set by cmp, so your jz does not work (more or less by accident). If you want to save the flags for later comparison, you could use pushf and popf, however this won't really work in your case since putchar will expect the character on the stack, not the flags.
Now, to answer the actual problem which you didn't state. I'll assume you want to print 's' two times. Here's how to do it properly:
mov eax, 2 ; init counter
print_loop:
push eax; save the counter since it will be trashed by putchar
push 's'
call putchar
add esp, 4 ; restore the stack pointer since putchar is cdecl
pop eax ; restore the saved counter
dec eax ; decrement it
jnz print_loop ; if it's not yet zero, do another loop
add esp, 4 can be replaced by another pop eax for slightly shorter code.

The result of doing a cmp is that flags get set, zf for zero, and so on. You can then either branch on whether or not the flag was set or use one of the set? instructions to have a value, e.g. the al register, set based on whether or not the flag was set.

Related

How do I handle the stack pointer register when returning from an assembly function call to a C program?

My program is composed of two files: main.c and core.s and runs on a 32 bit virtual machine of lubuntu linux.
Main.c takes in an integer and passes it to the assembly function void printFunc(int x). The assembly function in turn calls to a C function to check the parity of x. If x is even the function will print 4x and if x is odd it will print 8x. The print call must be done within the assembly function.
section .text
global printFunc
extern c_checkValidity
extern printf
section .data ; data section
fmt: db "%d", 10, 0 ; The printf format, "\n", '0'
printFunc:
push ebp ; code for handling stack I've seen from
mov ebp, esp ; other examples online
pushad
mov ebx, eax ; copy and input value
push eax ; Move input onto stack
call c_checkValidity ; Call C function, return value is in eax
cmp eax, 1 ; Check result, 1 indicates even
je multby4 ; If even, do mult by 4
jmp multby8 ; Otherwise odd, do mult by 8
multby4: ;INPUT WAS EVEN
sal ebx, 2 ; left shift by 2 is equivalent to multiplying by 4
jmp exitcode ; print and exit code
multby8: ;INPUT WAS ODD
sal ebx, 3 ; left shift by 3 is equivalent to multiplying by 8
jmp exitcode ; print and exit code
exitcode:
mov eax,ebx ; move value to eax to keep as default return value of func
push ebx ; Push final answer to the stack
push dword fmt ; Push print format to the stack
call printf ; Print answer
mov eax, ebx ; Copy final answer as return value
popad
mov esp, ebp ; return stack pointer to what it was before operation
pop ebp ; get rid of saved pointer
ret ; return state to caller
The integer input is received, parity tested, and printed to stdout correctly. A segfault occurs somewhere after call printf has successfully executed. When I use gdb to try and backtrace the segfault the report says "0x0804a0f in exitcode ()". Presumably this is the address of the code during operation that causes the segfault?
It is clear to me that I have failed to properly handle the stack pointer register (esp?) in some way. I've tried searching this site and others for examples of how to properly address the stack before returning control to the caller but to no avail. Certainly I would love to make the code work and any advice on how to fix the code is appreciated but I am primarily asking for an explanation on what I should be tracking and maintaining in general to return from an assembly function to a caller (extra appreciation if that explanation includes how to pass back values to the caller).

Isolating first command line arg assembly and modding it

I'm currently working with a nasm program in Assembly and I'm trying to write a program to determine if the first command line arg given is a leap year or not. I've successfully processed argument handling and the proper message displays when a user enters anything but one command line arg, but now I'm confused about how to "access" the year provided and mod it with numbers. Here is my code so far
global main
extern puts
extern printf
extern atoi
section .text
main:
push r13
push r14
sub rsp, 8
cmp rdi, 2
jne error1 ; jump if aguments != 1
jmp done
error1:
mov edi, badArgs
call puts
jmp done
done:
pop r14
pop r13
add rsp, 8
ret
badArgs:
db "Requires exactly one argument", 5, 0
The line in question occurs right after my jne line which checks for bad args. Now I want to isolate the argument (which I believe is located in the rsi register) and mod it with the number 4 to begin my leap year cheks. How do I isolate this value and mod it with 4?

Need some advice with NASM loop

I`m trying to make a while loop that prints from 0 through 10 but have some errors...
Compile with these:
nasm -f elf myprog.asm
gcc -m32 -o myprog myprog.o
Errors:
at output you can see 134513690.. lots of....
and at the last line a segmentation fault
This is the code:
SECTION .text
global main
extern printf
main:
xor eax,eax ; eax = 0
myloop:
cmp eax,10 ; eax = 10?
je finish ; If true finish
push eax ; Save eax value
push number ; push number value on stack
call printf
pop eax
inc eax ; eax + 1
add esp,80 ; Im not sure what is this
jmp myloop ; jump to myloop
number db "%d",10,0 ; This is how i print the numbers
finish:
mov eax,1
mov ebx,0
int 0x80
There's one real error in this code; the function call cleanup isn't quite right. I would change the myloop section to be like this:
myloop:
cmp eax,10 ; eax = 10?
je finish ; If true finish
push eax ; Save eax value
push number ; push number value on stack
call printf
add esp, 4 ; move past the `push number` line
pop eax
inc eax ; eax + 1
jmp myloop ; jump to myloop
The biggest difference is that instead of adding 80 to esp (and I'm not sure why you were doing that), you're only adding the size of the argument pushed. Also, previously the wrong value was getting popped as eax, but switching the order of the add and the pop fixes this.
A few problems, you need to push the "number" not as address, but as numeral.
push dword number
After you call printf, you need to restore the stack, ESP.
Basically when you "push" a register, it gets stored in the stack. Since you push twice (two arguments), you need to restore 8 bytes.
When you "pop eax", you're retrieving the top of the stack, which is "number", not the counter. Therefore, you just need to do
pop eax
pop eax
then there is no need to restore the ESP by adding since it is done by popping.
Basically, after the first iteration, eax points at an address, so it will never be equal to 10.
Further reading about Stack Pointer and Base Pointer:
Ebp, esp and stack frame in assembly with nasm

Pointers in assembly language

I am trying to understand how to use pointer in assembly. By reading some tutorials around internel,I think had undertantood some concepts. But when I'II go to try it,it did work. Below some attempts to translate C to ASM.
C
const char *s = "foo";
unsigned z = *(unsigned*)s;
if(!(z & 0xFF))
do_something();
if(!(z & 0xFFFF))
do_b_something();
(here's not full code,but it's a word-check,thefore,there is more two stmts which checks 0xFF0000,0xF000000 respectivily.
ASM:
mov ebp,str
mov eax,ebp
mov eax,[eax]
and eax,0xFF
cmp eax,0
je etc
mov eax,[eax]
and eax,0xFFFF
cmp eax,0
je etc
It returns a seg fault.
And the try:
mov eax,dword ptr [eax]
that's generated by gcc compiler and you can see it in some other assemblies code,returns
invalid symbol
on FASM assembler. It isn't really supported by the FASM or am I missing something?
I think this is what you are attempting to do:
mov ebp,str
mov eax,ebp
mov ebx,[eax]
test ebx,0xFF
jz low_byte_empty
do_something:
; some code here...
low_byte_empty:
test ebx,0xFFFF
jz low_word_empty
do_b_something:
; some code here.
low_word_empty:
Explanation:
First, as JasonD already mentions in his answer, you are loading a pointer to eax, then doing a logical and to it, then you are using the result still in eax to address memory (some memory offset in the range 0x0 ... 0xFF).
So what goes wrong in your code: you can't keep in the same register both a pointer to a memory address and a value at the same time. So I chose to load the value from [eax] to ebx, you can also use some other 32-bit general register (ecx, edx, esi, edi) according to your needs.
Then, you don't need to use cmp to check if a register is empty, because all cmp does is that it does the subtraction and sets the flags. But ZF (zero flag) is already set by and, so cmp is absolutely unnecessary here. Then, as cmp is not needed here and we do not need the result either, we only want to update the flags, it's better to use test. test does exactly the same logical AND as and does, the only difference being that test does not store the result, it only updates the flags.
It's not at all clear what you're trying to do in the original code - doesn't look right.
However this:
mov eax,[eax]
and eax,0xFF
cmp eax,0
je etc
mov eax,[eax]
Isn't going to work. You're overwriting the contents of EAX with the value stored at the address in EAX, manipulating that value, and then trying to reload it after the branch without restoring the original pointer.
Following variant is simpler, smaller, faster and uses only one register.
mov eax, str
mov eax,[eax]
test al, al
jz low_byte_empty
do_something_byte:
; some code here...
low_byte_empty:
test ah, ah
jz low_word_empty
do_something_word:
; some code here
low_word_empty:

How would I find the length of a string using NASM?

I'm trying to make a program using NASM that takes input from command line arguments. Since string length is not provided, I'm trying to make a function to compute my own. Here is my attempt, which takes a pointer to a string in the ebx register, and returns the length of the string in ecx:
len:
push ebx
mov ecx,0
dec ebx
count:
inc ecx
inc ebx
cmp ebx,0
jnz count
dec ecx
pop ebx
ret
My method is to go through the string, character by character, and check if it's null. If it's not, I increment ecx and go to the next character. I believe the problem is that cmp ebx,0 is incorrect for what I'm trying to do. How would I properly go about checking whether the character is null? Also, are there other things that I could be doing better?
You are comparing the value in ebx with 0 which is not what you want. The value in ebx is the address of a character in memory so it should be dereferenced like this:
cmp byte[ebx], 0
Also, the last push ebx should be pop ebx.
Here is how I do it in a 64-bit Linux executable that checks argv[1]. The kernel starts a new process with argc and argv[] on the stack, as documented in the x86-64 System V ABI.
_start:
pop rsi ; number of arguments (argc)
pop rsi ; argv[0] the command itself (or program name)
pop rsi ; rsi = argv[1], a pointer to a string
mov ecx, 0 ; counter
.repeat:
lodsb ; byte in AL
test al,al ; check if zero
jz .done ; if zero then we're done
inc ecx ; increment counter
jmp .repeat ; repeat until zero
.done:
; string is unchanged, ecx contains the length of the string
; unused, we look at command line args instead
section .rodata
asciiz: db "This is a string with 36 characters.", 0
This is slow and inefficient, but easy to understand.
For efficiency, you'd want
only 1 branch in the loop (Why are loops always compiled into "do...while" style (tail jump)?)
avoid a false dependency by loading with movzx instead of merging into the previous RAX value (Why doesn't GCC use partial registers?).
subtract pointers after the loop instead of incrementing a counter inside.
And of course SSE2 is always available in x86-64, so we should use that to check in chunks of 16 bytes (after reaching an alignment boundary). See optimized hand-written strlen implementations like in glibc. (https://code.woboq.org/userspace/glibc/sysdeps/x86_64/strlen.S.html).
Here how I would have coded it
len:
push ebx
mov eax, ebx
lp:
cmp byte [eax], 0
jz lpend
inc eax
jmp lp
lpend:
sub eax, ebx
pop ebx
ret
(The result is in eax). Likely there are better ways.

Resources