Related
This question already has answers here:
X86 NASM Assembly converting lower to upper and upper to lowercase characters
(5 answers)
X86 Assembly Converting lower-case to uppercase
(1 answer)
Closed 3 years ago.
I want to change the string to all caps, although I am having trouble getting the length of the input. What i have tried so far is moving the address of the message into a registrar then indexing through the string and also increment a counter variable. Then comparing the char in the address to a '.' (signifying the end of the message) and if its found not to be equal it will recall this block of statements. At least this is what I want my code to do. Not sure if this is even the right logic. I know there are alot of errors and its messy but I'm learning so please just focus on my main question. thank you! EDIT: the input i use is 'this is a TEST.'
;nasm 2.11.08
SYS_Write equ 4
SYS_Read equ 3
STDIN equ 0
STDOUT equ 1
section .bss
message resb 15
counter resb 2
section .data
msg1: db 'Enter input (with a period) that I will turn into all capitals!',0xa ;msg for input
len1 equ $- msg1
section .text
global _start
_start:
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, msg1 ; msg to print
mov edx, len1 ; len of message
int 0x80 ; Call the kernel
mov eax, SYS_Read ;system call to read input
mov ebx, STDIN ;file descriptor
mov ecx, message ;variable for input
mov edx, 15 ;size of message
int 0x80 ;kernel call
mov [counter], byte '0'
getLen:
mov eax, message
add eax, [counter]
inc byte [counter]
cmp eax, '.'
jne getLen
mov eax, SYS_Write ; this is to print the counter to make sure it got the right len
mov ebx, STDOUT
mov ecx, counter
mov edx, 2
int 0x80
jmp end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, [message]
;add eax, counter
cmp eax, 90
jg toUpper
toUpper:
sub eax, 32
mov [message], eax
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, message ; Put the offset of hello in ecx
mov edx, 10 ; helloLen is a constant, so we don't need to say
int 0x80 ; Call the kernel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 0x80 ;
Task: output the number in hexadecimal form to the console. After that print some string (let it be "String after num").
The first part is successful, but the second is not.
The input number is stored in memory by the num label.
String is stored in memory by the line label.
String length - lines.
Code:
global _start
section .data
num db 01111110b
temp db 0
line db 10, "String after num", 10
lines equ $-line
section .text
_start:
call write_hex ; write num in hex format
mov eax, 4 ; write "Hello world!"
mov ebx, 1 ;
mov ecx, line ;
mov edx, lines ;
int 80H ;
mov eax, 1 ; exit
xor ebx, ebx
int 80H
write_hex:
mov eax, [num]
mov [temp], eax
shr byte [num], 4
call to_hex_digit
call write_digit
mov eax, [temp]
mov [num], eax
and byte [num], 1111b
call to_hex_digit
call write_digit
ret
to_hex_digit:
add [num], byte '0'
cmp [num], byte '9'
jle end
add [num], byte 7
end: ret
write_digit:
mov eax, 4
mov ebx, 1
mov ecx, num
mov edx, 1
int 80H
ret
Output:
Thanks for any help.
I used an invalid register to store a temporary value. I replaced the register which will work with the temp from eax to al. See Jester's answer.
I am writing a MASM program using the Irvine32 Library from my textbook. I want to line up my printed columns, but I couldn't finds anything on how to terminate a string with a tab-stop, /t for C/C++, so I made a procedure that determines how many decimal places the number has and assigns the spacer string variable accordingly.
My issue is when trying to assign spacer a new string, I get assembling errors. I have tried
mov spacer, "New String",0
and
mov spacer, "New String"
as well as assigning "New String" to a variable and assigning spacer that variable as well as that variables OFFSET. I now have it where the variables OFFSET is moved into edx but I can't move edx into the other variable.
I would greatly appreciate the help and any information to help be better understand why this doesn't work in assembly or MASM in particular. Thanks
Procedure in question:
; Define the spacer based on the places in x
spacer_choice proc
cmp x, 10
JB SC1
cmp x, 100
JB SC2
mov edx, OFFSET hundo_spacer
JMP SC3
SC1:
mov edx, OFFSET one_spacer
JMP SC3
SC2:
mov edx, OFFSET ten_spacer
JMP SC3
SC3:
mov spacer, OFFSET edx
RET
spacer_choice endp
Output:
1>------ Build started: Project: MASM4, Configuration: Debug Win32 ------
1> Assembling composite.asm...
1>composite.asm(209): error A2032: invalid use of register
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\BuildCustomizations\masm.targets(50,5): error MSB3721: The command "ml.exe /c /nologo /Sg /Zi /Fo"Debug\composite.obj" /Fl"MASM4.lst" /I "c:\Irvine" /W3 /errorReport:prompt /Tacomposite.asm" exited with code 1.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Full Code:
INCLUDE Irvine32.inc
.data
; ----- GLOBALS
n_comps DWORD ?
; ----- INTRO VALUES
; Greeting the User
title_prompt BYTE "Welcome to Prog. 4, my name is Zach", 10, 13, 0
name_prompt BYTE "What should I call you?: ", 0
username BYTE 21 DUP(0)
user_greet BYTE "Hello, ", 0
; Instructing the User
one_instruct BYTE "We are going to calculate all the composite numbers from 1 to n.", 10, 13, 0
two_instruct BYTE "N is the number you enter. That number has to be an integer,", 10, 13, 0
three_instruct BYTE "and in the range of 1 to 400.", 10, 13, 0
; ----- INPUT VALUES
; Prompts
int_prompt BYTE "How many composite numbers do you want to display? 1 to 400: ", 0
bad_prompt BYTE "Your Input was bad, try again", 10, 13, 0
; Constants
MAX_VAL = 400
MIN_VAL = 1
; ----- CALCULATE
x DWORD ?
spacer BYTE ?
count DWORD ?
; ----- SPACER_CHOICE
one_spacer BYTE ", ", 0
ten_spacer BYTE ", ", 0
hundo_spacer BYTE ", ", 0
; ----- OUTRO
farewell BYTE "Hope you've had fun printing composites! Goodbye, ", 0
.code
main proc
call intro
call input
call calculate
call outro
invoke ExitProcess, 0
main endp
; Greet the User and get their name
intro proc
; Greet
mov edx, OFFSET title_prompt
call WriteString
; Prompt for username
mov edx, OFFSET name_prompt
call WriteString
mov edx, OFFSET username
mov ecx, SIZEOF username
call ReadString
mov edx, OFFSET user_greet
call WriteString
mov edx, OFFSET username
call WriteString
call Crlf
; Intruct the User
mov edx, OFFSET one_instruct
call WriteString
mov edx, OFFSET two_instruct
call WriteString
mov edx, OFFSET three_instruct
call WriteString
intro endp
; Get User's Input. Validate if Between Min and Max
input proc
; Prompt for user input
I1:
mov edx, OFFSET int_prompt
call WriteString
mov eax, 0
call ReadInt
call Crlf
; Check if less than MAX_VAL
cmp eax, MAX_VAL
JA I4
JMP I3
I3:
; Check if greater than MIN_VAL
cmp eax, MIN_VAL
JB I4
JMP I2
I4:
; EAX is incorrect
; Loop
mov edx, OFFSET bad_prompt
call WriteString
loop I1
; Good Input
; Set n_comps to eax
I2:
mov n_comps, eax
mov eax, 0
RET
input endp
; X is not divisible by 2 or 3, is prime
calculate proc
mov ecx, 400
mov x, 1
C1:
; Check if X is less than, or equal to, 3
cmp x, 3
JBE C2
C4:
; Check if X is divisible by 2
mov edx, 0
mov eax, x
mov ebx, 2
div ebx
cmp edx, 0
JE C3
; Check if X is divisible by 3
mov edx, 0
mov eax, x
mov ebx, 3
div ebx
cmp edx, 0
JNE C2
C3:
; Is composite, Print number
mov eax, x
cmp count, 10
JNE C5
call Crlf
mov count, 0
C5:
call WriteInt
call spacer_choice
mov edx, OFFSET spacer
call WriteString
add count, 1
C2:
; RET if X == N
mov eax, n_comps
cmp x, eax
JNE C6
RET
C6:
; Increment and LOOP
add x, 1
LOOP C1
calculate endp
; Define the spacer based on the places in x
spacer_choice proc
cmp x, 10
JB SC1
cmp x, 100
JB SC2
mov edx, OFFSET hundo_spacer
JMP SC3
SC1:
mov edx, OFFSET one_spacer
JMP SC3
SC2:
mov edx, OFFSET ten_spacer
JMP SC3
SC3:
mov spacer, OFFSET edx
RET
spacer_choice endp
; Say Goodbye
outro proc
mov edx, OFFSET farewell
call WriteString
mov edx, OFFSET username
call WriteString
call Crlf
outro endp
end main
I added the ASCII horizontal tab, 9, to the end of spacer, and that removed the need for the spacer_choice procedure.
Spacer now is declared as: spacer BYTE ",", 9, 0
;This program reverses a string.
INCLUDE Irvine32.inc
.data
aName BYTE "Abraham Lincoln",0
nameSize = ($ - aName) - 1
.code
main PROC
; Push the name on the stack.
mov ecx,nameSize
mov esi,0
L1: movzx eax,aName[esi] ; get character
push eax ; push on stack
inc esi
Loop L1
; Pop the name from the stack, in reverse,
; and store in the aName array.
mov ecx,nameSize
mov esi,0
L2: pop eax ; get character
mov aName[esi],al ; store in string
inc esi
Loop L2
; Display the name.
mov edx,OFFSET aName
call Writestring
call Crlf
exit
main ENDP
END main
I finished the first part of the problem which was making a Reverse String program but now I need to modify the program so the user can input a string containing between 1 and 50 characters. Im not to sure how to do this and was wondering if someone could help out. This is in assembly language btw
You can use ReadString from irvine32.lib. Therefor you have to change nameSize to a variable and to increase the size of aName.
I did it for you ;-) :
;This program reverses a string.
INCLUDE Irvine32.inc
.data
aName BYTE 51 DUP (?)
nameSize dd ?
.code
main PROC
mov edx, OFFSET aName
mov ecx, 50 ;buffer size - 1
call ReadString
mov nameSize, eax
; Push the name on the stack.
mov ecx,nameSize
mov esi,0
L1: movzx eax,aName[esi] ; get character
push eax ; push on stack
inc esi
Loop L1
; Pop the name from the stack, in reverse,
; and store in the aName array.
mov ecx,nameSize
mov esi,0
L2: pop eax ; get character
mov aName[esi],al ; store in string
inc esi
Loop L2
; Display the name.
mov edx,OFFSET aName
call Writestring
call Crlf
exit
main ENDP
END main
I keep getting a segmentation fault error when running my code. Everything has compiled well, but I can't seem to get it to do what I want. The program is to ask the user to enter 3 integers, then ask the user what they think the average of the numbers would be, take that into account and then come back with whether or not the user guessed correctly
segment .data
;
; Output strings
;
prompt1 db "Enter a positive integer: ", 0
prompt2 db "Enter a second positive integer: ", 0
prompt3 db "Enter a third positive integer: ", 0
prompt4 db "Enter a guess of their average: ", 0
outmsg1 db "You entered ", 0
outmsg2 db " and ", 0
outmsg3 db " and ", 0
outmsg4 db "You guessed that the average is ", 0
outmsg5 db "You did you guess correctly? (0 = no, 1 = yes)", 0
avermsg db "The average of the numbers is ", 0
segment .bss
input1 resd 1
input2 resd 1
input3 resd 1
input4 resd 1
guess resd 1
segment .text
Global main
main:
enter 0,0 ; setup routine
pusha
mov eax, prompt1 ; print out prompt1
call print_string
call read_int ; read integer
mov [input1], eax ; store integer into input1
mov eax, prompt2 ; print out prompt2
call print_string
call read_int ; read integer
mov [input2], eax ; store integer into input2
mov eax, prompt3 ; print out prompt3
call print_string
call read_int ; read integer
mov [input3], eax ; store integer into input3
mov eax, prompt4 ; print out prompt4
call print_string
call read_int ; read integer
mov [guess], eax
mov eax, [input1] ; eax = dword at input1
add eax, [input2] ; eax += dword at input2
add eax, [input3] ; eax += dword at input3
mov ebx, 3
div ebx ; divides the sum by 3
mov ecx, eax ; freeing up eax, puts quotient into ecx
dump_regs 1 ; print out register values
; next print out results
mov eax, outmsg1
call print_string ; print out first message
mov eax, [input1]
call print_int
mov eax, outmsg2
call print_string ; print out second message
mov eax, [input2]
call print_int
mov eax, outmsg3
call print_string ; print out thrid message
mov eax, [input3]
call print_int
mov eax, outmsg4
call print_string ; print out fourth message
mov eax, [input4]
call print_int
xor ebx, ebx
cmp ecx, [guess]
sete bl
neg ebx
mov edx, ebx
and ecx, edx
not ebx
and ebx, [guess]
or edx, ebx
mov eax, outmsg5
call print_string
mov ecx, eax
call print_int
mov eax, [avermsg]
call print_string ; print out final message
mov ecx, edx
call print_int ; print out average of ebx
call print_nl ; print new line
popa
mov eax, 0 ; return back to C
leave
ret
It is not easy to pinpoint the problem without knowing the compiler you use.
Segmentation fault hapens in protected mode, when you try to access a segment you have no permissions to access.
You declare 3 diferent segments here. You have to make sure your ds register is initialized to your .data segment, before calling print_string.
It also seems problematic that after read_int you save the data to the input1 variable which seems to be in a different segment than that you used for printing the message, but you do not change ds.
I'm not familiar how exactly your compiler handles these segments, so please give a link to its documentation.
div ebx
the problem seems to be here. You have to zero out edx since is is the high order word of the divisor, so probably you're getting something like a division overflow exception.
If this isn't the case probably the problem is in some of your I/O routines