I have some code in assembly which behaves a little bit strange. I have a C extern function that calls with asm another function from an .asm file. This C function puts on the stack three addresses used by my function from .asm file. All went well untill this appeared:
; Let's say we take from the stack first parameter from my C function.
; This parameter is a string of bytes that respect this format:
; - first 4 bytes are the sign representation of a big number
; - second 4 bytes are the length representation of a big number
; - following bytes are the actual big number
section .data
operand1 dd 0
section .text
global main
main:
push ebp
mov ebp, esp
mov eax, [ebp + 8] ; Here eax will contain the address where my big number begins.
lea eax, [eax + 8] ; Here eax will contain the address where
; my actual big number begins.
mov [operand1], eax
PRINT_STRING "[eax] is: "
PRINT_HEX 1, [eax] ; a SASM macro which prints a byte as HEX
NEWLINE
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [operand1]
NEWLINE
leave
ret
When running this code, I get at the terminal the correct output for [eax], and for [operand1] it keeps printing a number which will not change if I modify that first parameter of my C function. What am I doing wrong here?
I made an understandable mistake. When doing:
mov [operand1], eax
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [operand1]
NEWLINE
This code prints the first byte of the content (which is the address where my actual big number begins) contained at the address where this local variable (operand1) resides. In order to get the actual value which resides at [operand1] I had to do this:
mov ebx, [operand1]
PRINT_STRING "[operand1] is: "
PRINT_HEX 1, [ebx]
NEWLINE
Related
In the first loop I fill the array, then I want to print this array, but I'll have an error. It's Segmentation fault. I just change ecx register, since is my counter for _loop2.
extern printf
SECTION .bss
array resb 10
SECTION .data
fmt: db "array[%d] = %d", 10, 0 ; The printf format, "\n",'0'
SECTION .text
global main
main:
mov ecx, 0
_loop:
inc ecx
mov [array + ecx * 4], ecx
cmp ecx, 10
jnz _loop
mov ecx, 0
_loop2:
jmp print
add ecx, 1
cmp ecx, 10
jnz _loop2
ret
print:
;push ebp ; set up stack frame
;mov ebp, esp
push ecx
push dword [array + ecx * 4] ; value of variable a SECOND
push dword fmt ; address of ctrl string
call printf ; Call C function
add esp, 8 ; stack (4 * 2)
;mov esp, ebp ; takedown stack frame
;pop ebp ; same as "leave" op
mov eax,0 ; normal, no error, return value
;ret ; return
Several issues as mentioned in comments:
array resb 10 will reserve space for 10 bytes, but you want to store 10 dwords there (40 bytes). Change to array resd 10.
(Pointed out by Sep Roland) In _loop you have an off-by-one bug; since the inc is done before the mov you will access the dwords at [array+4], [array+8], ... [array+40], where the last one is out of range. This is like doing int array[10]; for (i=1; i <= 10; i++) array[i]=i; in C, and is incorrect for exactly the same reason. One fix would be to do mov [array + ecx * 4 - 4], ecx instead.
After _loop2 you have jmp print, which will transfer control to print and never come back. Since you apparently want to call print as a subroutine and continue executing with add ecx, 1 ; cmp ecx, 10, etc, you need to call print instead of jmp. And also uncomment the ret at the end of print so that it will actually return. Subroutines in assembly language don't automatically return unless you actually execute ret; otherwise the CPU will just continue executing whatever garbage happens to be next in memory.
You have a push ecx to save the value of ecx before the call to printf, which is good since printf will overwrite that register, but you need to pop ecx afterwards to get that value back and put the stack back to where it was.
Specifically, the pop ecx should follow the add esp, 8; a stack is a last-in-first-out structure, and the push ecx was before the pushing of the printf arguments, so you need to pop ecx after removing those arguments from the stack.
The mov eax, 0 as a return value at the end of print is unnecessary since you never use it anywhere else.
With these changes the code works as it should.
I am having an issue with this code snippet of a problem. My expected output is (after the intro):
Please enter an unsigned number: (user input)
.
.
.
Repeat ten times
The output that I am getting is :
Please enter an unsigned number: 10
10 <--- this is displaying instead of "Please enter an unsigned number: "
Any idea why this problem might be happening?
;getString should display a prompt, then get the user’s keyboard input into a memory location
getString MACRO buffer
push edx ;Save edx register
mov edx, OFFSET buffer
call WriteString
call ReadString
pop edx
ENDM
;displayString should the string stored in a specified memory location.
displayString MACRO buffer
push edx
mov edx, OFFSET buffer
call WriteString
call crlf
ENDM
.data
intro_1 BYTE "PROGRAMMING ASSIGNMENT 5: Designing low-level I/O procedures",0
intro_2 BYTE "Written by: Eric Walters",0
intro_3 BYTE "Please provide 10 unsigned decimal integers.",0
intro_4 BYTE "Each number needs to be small enough to fit inside a 32 bit register.",0
intro_5 BYTE "After you have finished inputting the raw numbers I will display a list",0
intro_6 BYTE "of the integers, their sum, and their average value.",0
data_1 BYTE "Please enter an unsigned number: ",0
array DWORD 10 DUP(?)
.code
main PROC
;Introduction
displayString intro_1
displayString intro_2
displayString intro_3
displayString intro_4
displayString intro_5
displayString intro_6
push OFFSET array
call getString1
;readVal
exit
main ENDP
getString1 PROC
push ebp
mov ebp, esp
mov ecx, 9
mov esi, [ebp + 8]
getString2:
getString data_1
mov [esi], eax
add esi, 4
call crlf
dec ecx
jmp getString2
ret
getString1 ENDP
END main
I suspect the problem is in some parameter being inadvertently passed into read string pointing at the address where data_1 is stored. For example, if edx is pointing at data_1 when you mov the OFFSET into it, and the WriteString is looking at edx for the address of the data to write, ReadString is looking at edx for the address to store the line in once it is read. So the ReadString is overwriting your sentence in data_1 with the number you entered and an end of line marker. Then the next time the WriteString PROC is called, it is reading in that number.
To fix this, create a .data? field called input_data or whatever you like, and point edx at it after the WriteString call but before the ReadString call.
Just an aside, but I also think you need to change your line after "dec ecx" to read "jnz getString2", not "jmp getString2". Otherwise I cannot see you ever escaping the loop no matter what value ecx reaches.
EDIT: Wait, I see, you have an array set up for that already. I think you just need to point to it before calling ReadString.
I'm writing a while loop in assembly to compile in the Linux terminal with nasm and gcc. The program compares x and y until y >= x and reports number of loops at the end. Here's the code:
segment .data
out1 db "It took ", 10, 0
out2 db "iterations to complete loop. That seems like a lot.", 10, 0
x db 10
y db 2
count db 0
segment .bss
segment .text
global main
extern printf
main:
mov eax, x
mov ebx, y
mov ecx, count
jmp lp ;jump to loop lp
lp:
cmp ebx, eax ;compare x and y
jge end ;jump to end if y >= x
inc eax ;add 1 to x
inc ebx ;add 2 to y
inc ebx
inc ecx ;add 1 to count
jp lp ;repeat loop
end:
push out1 ;print message part 1
call printf
push count ;print count
call printf
push out2 ;print message part 2
call printf
;mov edx, out1 ;
;call print_string ;
;
;mov edx, ecx ;these were other attempts to print
;call print_int ;using an included file
;
;mov edx, out2 ;
;call print_string ;
This is compiled and run in the terminal with:
nasm -f elf test.asm
gcc -o test test.o
./test
Terminal output comes out as:
It took
iterations to complete loop. That seems like a lot.
Segmentation fault (core dumped)
I can't see anything wrong with the logic. I think it's syntactical but we've only just started learning assembly and I've tried all sorts of different syntax like brackets around variables and using ret at the end of a segment, but nothing seems to work. I've also searched for segmentation faults but I haven't found anything really helpful. Any help would be appreciated because I'm an absolute beginner.
The reason it crashes is probably that your main function doesn't have a ret instruction. Also be sure to set eax to 0 to signal success:
xor eax, eax ; or `mov eax, 0` if you're more comfortable with that
ret
Additionally, global variables designate pointers, not values. mov eax, x sets eax to the address of x. You need to write back to it if you want anything to happen (or not use global variables).
Finally, you're calling printf with a single non-string argument:
push count ;print count
call printf
The first argument needs to be a format string, like "%i". Here, count is a pointer to a null byte, so you get nothing instead. Off my head, you should try this:
out3 db "%i ", 0
; snip
push ecx
push out3
call printf
I think your problem might just be that you are referencing the addresses of your constants and not their intrinsic value. One must think of a label in nasm as a pointer rather than a value. To access it you just need to use [label]:
segment .data
x dw 42
segment .text
global main
extern printf
main:
mov eax, x
push eax
call printf ; will print address of x (like doing cout<<&x in C++)
mov eax, [x]
push eax
call printf ; will print 42
sub esp, 8
xor eax, eax
ret
PS:I don't think anyone has mentioned it but volatile registers are modified very often when calling external code (C or C++ or other) since at compilation those functions you use are "translated" to assembly and then linked with your asm file. The PC is not a human so it is not distinguishing between what was written in high-level or low-level, the processor is just reading opcodes and operands stored in registers and memory, hence why an external function when using low-level language (call printf) is going to modify (or not! always depends on compiler and architecture) registers that you are also using.
To solve this there are various solutions:
You check what registers are not being modified by using gcc your_c_file.c -S and then in the file your_c_file.swill be the pre-prepared assembly code your compiler has produced from your C file. (It tends to be quite hard to figure out what is what and if you are going to use this method check out Name Mangling, to see how func names will be changed.)
Push all the registers you want to save to stack, and then after the call pop them back to their registers keeping in mind LIFO method.
Use the instructions PUSHA and POPAwhich push or pop all registers respectively.
This is the NASM manual chapter 3 which explains the basis of the language to use: http://www.csie.ntu.edu.tw/~comp03/nasm/nasmdoc3.html
Hope you managed to solve it.
I am using NASM for compiling my ASM program and I am having trouble figuring out how to print an entire array on a single line (without necessarily knowing how big the array is) using a loop. Whenever I create a loop with printf it prints the values on multiple lines instead of one line. Any idea how to make printf print multiple values of an array on a single line using a loop? I get values 1-9 but all on a different line instead of the same line. This is to be done without using external libraries other than: the printf c library. Any help would be most appreciated. The code I have is below.
extern printf
SECTION .data ; Data section, initialized variables
array: dd 1, 2, 3, 4, 5, 6, 7, 8, 9, 0; this is a test array for testing purposes
arrayLen: dd 9 ; length of array
aoutput: db "%d", 10, 0 ; output format
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
push ebp ; set up stack frame
mov ebp,esp
mov ecx, [arrayLen] ; loop counter set up
mov esi, 0 ; counter to increment set up for looping through array
.loop:
push ecx ; make sure to put ecx (counter) on stack so we don't lose it when calling printf)
push dword [array + esi] ; put the value of the array at this (esi) index on the stack to be used by printf
push dword aoutput ; put the array output format on the stack for printf to use
call printf ; call the printf command
add esp, 8 ; add 4 bytes * 2
pop ecx ; get ecx back
add esi, 4
loop .loop
mov esp, ebp ; takedown stack frame
pop ebp ; same as "leave" op
mov eax,0 ; normal, no error, return value
ret ; return
The only thing that determines whether something is printed on a single line or multiple, is if you print a newline character (\n) or not.
Here, when you say 10, that is the ASCII value for a Line Feed. If you change this:
aoutput: db "%d", 10, 0
to this:
aoutput: db "%d ", 0
your values will be separated by spaces, instead of by new lines.
After the final value in the sequence, you can print a lone newline character:
push 0x0A ; New line character
call putchar
I figured out this (which is the same as the other answer, I just found it out before I saw it was posted).
I figured it out, I changed the format definition to:
aoutput: db "%d ", 0 ; output format
from:
aoutput: db "%d ", 10, 0 ; output format
and just added an newline format to add a new line at the end.
newline: db "", 10, 0 ; newline format
The problem is that you are outputting a line feeds after each element.
What follows are two solution. Neither of them suffer from the problem of leaving a trailing blank space as the two existing solutions do.
Note that I made a slight rearrangement of the loop to allow empty arrays. Allowing empty arrays is a good practice even if it's not necessary since it doesn't require any extra instructions.
Solution 1: Use "%d\n" as the format if it's the last element or "%d " otherwise.
This is good if you don't want to print the line feed for empty arrays.
format1: db "%d ", 0
format2: db "%d", 10, 0
jmp .loop3
.loop1:
mov eax,format1
cmp ecx,1
jnz .loop2
mov eax,format2
.loop2
push ecx
push dword [array + esi]
push dword eax
call printf
add esp, 8
pop ecx
add esi, 4
.loop3:
loop .loop1
Solution 2: Use "%d" as the format if it's the first element. Use " %d" as the format otherwise. Print a line feed after the loop.
This is good if you want to print the line feed even for empty arrays.
format1: db "%d", 0
format2: db " %d", 0
mov eax, format1
jmp .loop2
.loop1:
push ecx
push dword [array + esi]
push dword eax
call printf
add esp, 8
pop ecx
add esi, 4
mov eax, format2
.loop2:
loop .loop1
push 10
call putchar
Pardon any errors; the x86 didn't have an eax register the last time I wrote assembly for it. The logic should be evident in any case.
I made a simple program which will just push a number and display it on the screen but
don't know what is going wrong
section .data
value db 10
section .text
global main
extern printf
main:
push 10 //can we push value directly on stack?
call printf
add esp,4
ret
Getting Segmentation fault for above.
section .data
value db 10
section .text
global main
extern printf
main:
push [value]
call printf
add esp,4
ret
In second version will be pushing value pointed to by value variable on to stack
But getting "operation size not specified"
Yes, you can push any DWORD value (in 32-bit assembler) onto the stack.
The problem in the first code fragment is that printf expects the first argument to be a format string (in C, you'd write printf("%d\n", 10);). So something like
section .data
fmt db "%d", 10, 0
...
push 10
push fmt
call printf
add esp, 8
will work.
In the second code fragment, instead of push [value] you should write push dword [value], but that's not correct if your value variable is a single byte. Either declare it as a DWORD (dd), or perform
movsx eax, byte [value] ; if it's a signed integer; movzx for unsigned
push eax
And one more thing. When calling printf (or any of the C library functions), beware of stack alignment. Some platforms require that stack is 16-byte aligned at the time of a function call (this is necessary for correct execution of optimized CPU instructions like SSE). So, to make the stack aligned:
push ebp
mov ebp, esp
sub esp, 8 ; reserve 8 bytes for parameters
and esp, -16 ; align the stack (the reserved space can increase)
mov dword [esp], fmt ; put parameters into stack
mov dword [esp+4], 10
call printf
mov esp, ebp ; restore stack
pop ebp