How can I convert from ascii to integer?
data
asd:
.int 32
.text
.globl _start
_start:
movl $4, %eax
movl $1, %ebx
movl $1,(asd)
add $48,(asd)
movl $asd, %ecx
movl $4, %edx
int $0x80
# Exit the program
movl $1, %eax
movl $0, %ebx
int $0x80
The code is writing an ascii value, and I think that if I can add 48 to value. I can write, but I can't print, a two-stage number "for example 53 or 156". How can I print?
It's usually best to think about a high level language version first. If the number has n digits and is stored in array a, then we'd want:
char *p = a;
unsigned val = 0;
while (n > 0) {
n--;
val = 10 * val + (*p++ - '0');
}
So let's say %esi is p above %eax is val, and %ecx is n.
Translate line by line to keep it as simplistic and literal as possible:
movl $n, %ecx
movl $a, %esi
xorl %eax, %eax # val = 0
eval_while_cond:
testl %ecx, %ecx # if (n <= 0)
jle done # goto done
subl $1, %ecx # n--
movl %eax, %ebx # tmp1 = val
imul $10, %ebx # tmp1 = 10 * tmp1
movzbl (%esi), %eax # tmp2 = *p
addl $1, %esi # p++
subl $'0, %eax # tmp2 = tmp2 - '0'
addl %eax, %ebx # val = tmp2 + tmp1
jmp eval_while_cond
done:
# result is now in %eax
Note this is just a general methodology for getting functional assembly language. This isn't optimized in any way. The tricks needed to get optimal performance are a whole other topic.
The other options is to use a compiler (e.g. https://godbolt.org/z/WzGYjePzx) with light optimization like -O1, -Og, or -Os to get somewhat-readable asm (although in this case they use not-totally-obvious tricks with LEA to multiply by 10 and subtract '0' (48), or they make a mess with weird loop conditions.) See also How to remove "noise" from GCC/clang assembly output?
Related
I don't know why my program doesn't show the result of the sum of elements in the stuck. It just shows the string '-----'
I'm working on Linux.
.data
#################################
tabEntier : .long 3, 4, 2, 10, 16, 5, 6 #long = 4
maVar: .space 4
msgFin: .string "\n-----\n"
taillemsgFin = . - msgFin
################################
.text
.global _start
_start:
movl $3, %eax # eax ?
movl $0, %ebx # ebx ?
movl $tabEntier, %ecx # ecx ?
additionne:
addl (%ecx), %ebx # ebx ?
addl $4, %ecx # ecx ?
decl %eax # eax ?
jnz additionne
stocke:
movl %ebx, maVar
messageSortie:
movl $4, %eax
movl $1, %ebx
movl $msgFin,%ecx
movl $taillemsgFin,%edx
int $0x80
sortie:
movl $0, %ebx
movl $1, %eax
int $0x80
The result of the sum must be shown after '------' message
I don't know why my program don't show the result of the sum
It's because you don't actually have any code for outputting that. You syscall-4 to output the ---- string, then you immediately syscall-1 to exit.
If you want to output an integral value as well, you're going to need some code to do it. While modern CPUs have speculative execution, that doesn't mean speculating on what you really wanted to do :-)
You may also want to check what you're loading into eax. This seems to be the count of elements and there are seven in the list, but you only process the first three. No doubt you would have found that once you'd successfully output the sum but I thought I'd mention it anyway.
In terms of the code required to fix your issue, I include a small utility function for printing of signed longs, along with a test harness so that you can see it in action.
The test harness is a simple bash script which processes a series of test data items, injecting them in turn into the actual test program:
#!/bin/bash
# Selected test points, and some random ones.
testdata="0 1 -1 9 10 -9 -10 99 100 2147483647 -2147483648"
for i in {1..10} ; do
testdata="${testdata} ${RANDOM} $((0 - ${RANDOM}))"
done
# Do each test item.
for item in ${testdata} ; do
# Morph the asm template to create actual asm file,
# then assemble and link.
sed "s/XYZZY/${item}/" prog.in >prog.asm
as --32 -o prog.o prog.asm
ld -melf_i386 -o prog prog.o
# Test that output is as expected.
result="$(./prog)"
if [[ "${item}" == "${result}" ]] ; then
echo "Okay ('${item}')"
else
echo "BAD ('${item}' -> '${result}'"
fi
done
The code for testing this is in a template prog.in so it can be processed by that test harness to produce one with the actual test item. The file contains:
.data
numOut: .string "2147483648" # Largest signed-32 magnitude.
numEnd:
numLast= numEnd - 1
negOut: .string "-" # Negative prefix.
# ======================================================================
# Actual function for output of signed long in EAX.
.text
outLong: push %eax # Save registers.
push %ebx
push %ecx
push %edx
cmpl $0, %eax
je olZero # Zero special case.
jg olPos # Already positive.
push %eax # Negative handled here.
movl $4, %eax # SysWrite "-".
movl $1, %ebx
movl $negOut, %ecx
movl $1, %edx
int $0x80
pop %eax
negl %eax # Then negate.
olPos: movl $numEnd, %ecx # Last character placed.
olStore: movl $0, %edx # eax = edx:eax / 10, remainder -> edx
movl $10, %ebx
divl %ebx
addl $'0', %edx # Turn into ASCII and store.
decl %ecx
movb %dl, (%ecx)
cmpl $0, %eax # Continue until zero.
jnz olStore
jmp olPrint
olZero: movl $numLast, %ecx # Load 0 into buffer.
movb $'0', (%ecx)
olPrint: movl $4, %eax # SysWrite call.
movl $1, %ebx # File descriptor 1.
movl $numLast, %edx # Calculate length.
incl %edx
subl %ecx, %edx
int $0x80 # And print.
pop %edx # Clean up and return.
pop %ecx
pop %ebx
pop %eax
ret
# ======================================================================
# Test harness.
.global _start
_start: movl $XYZZY, %eax # Load up test value.
call outLong
movl $1, %eax # SysExit, success.
movl $0, %ebx
int $0x80
The output of one particular run of the test harness follows:
Okay ('0')
Okay ('1')
Okay ('-1')
Okay ('9')
Okay ('10')
Okay ('-9')
Okay ('-10')
Okay ('99')
Okay ('100')
Okay ('2147483647')
Okay ('-2147483648')
Okay ('3700')
Okay ('-30889')
Okay ('19074')
Okay ('-19825')
Okay ('22601')
Okay ('-19364')
Okay ('9291')
Okay ('-24785')
Okay ('28133')
Okay ('-2892')
Okay ('20544')
Okay ('-10782')
Okay ('20878')
Okay ('-28479')
Okay ('13808')
Okay ('-9415')
Okay ('17693')
Okay ('-6797')
Okay ('16385')
Okay ('-10299')
In terms of what you need to add to your code, it's basically everything except the test harness at the end. Then, you call it with a simple:
mov $42, %eax # Load EAX however you desire.
call outLong # And print it.
This code reads data from an inputfile character by character and it writes to another file.
It should stop to read and write once it finds a character with value equal to 3.
I said should because the program doesn't stop once it finds a value equal to 3, instead it continues to read until the end of file.
Inputfile is like: 2 4 5 3 1 8
My code is:
.section .data
varInputHandle: .long 100
varOutputHandle: .long 100
varExitCode: .long 1
cont: .long 1
.section .bss
.lcomm varBuffer, 1
.section .text # declaring our .text segment
.globl _start # telling where program execution should start
_start:
popl %eax # Get the number of arguments
popl %ebx # Get the program name
# open input file first
popl %ebx # Get the first actual argument - file to read
movl $5, %eax # open
movl $0, %ecx # read-only mode
int $0x80
movl %eax, varInputHandle #store input file handle to memory
#open output file, make it writable, create if not exists
popl %ebx # Get the second actual argument - file to write
movl $5, %eax # open
movl $0101, %ecx # create flag + write only access (if google is telling me truth)
movl $0666, %edx #permissions for out file as rw-rw-rw-
int $0x80
movl %eax, varOutputHandle #store output file handle to memory
contToZero:
movl $0, cont
processingLoop:
incb cont
#read single char to varBuffer
movl $3, %eax
movl varInputHandle, %ebx
movl $varBuffer, %ecx
movl $1, %edx
int $0x80
#if no char was read (EOF?), jmp finishProcessing
cmpl $0, %eax
jz finishProcessing # looks like total success, finish cleanly
cmpl $3, varBuffer // this instruction is never true, don't know why
je exitToOs
#write it
movl $4, %eax
movl varOutputHandle, %ebx # file_descriptor
movl $varBuffer, %ecx
movl $1, %edx
int $0x80
# done, go for the next char
goForTheNextChar:
jmp processingLoop
finishProcessing:
movl $0, varExitCode #everything went OK, set exit code to 0
exitToOs:
movl varOutputHandle, %ebx # file_descriptor
movl varInputHandle, %ebx
movl $1, %eax
movl varExitCode, %ebx
int $0x80
closeFile:
cmpl $-1, %ebx
movl $6, %eax #sys_close
int $0x80
cmpl $3, varBuffer seems to never be true therefore I can't jump to exitToOs.
In your code you have:
cmpl $3, varBuffer
This can never be true because you do not have binary data in your file.
When you read character by character, you are reading ASCII values. In order to properly make this comparison you must do one of two things:
Convert the character read from ASCII to decimal
Compare the read value to an ASCII value
Since you are relying on $0 to identify when you have read zero bytes, I would suggest that you take the (easier) approach of checking for the ASCII value that you would like to find. In your case this would be:
cmpb $'3', varBuffer # Compare character to 0x33 / 51 / "3"
I'm writing an assembly program with GAS compiler and AT&T syntax.
I have 2 files: one to read from and another one to write in.
From terminal i launch the program in this way: ./myprogram inputfile.txt outputfile.txt
Now I want to read input data character by character and this is how I'm trying to do it:
.section .data
buff_size: .long 1
.section .bss
.lcomm buff, 18
.section .text # declaring our .text segment
.globl _start # telling where program execution should start
_start:
popl %eax # Get the number of arguments
popl %ebx # Get the program name
popl %ebx # Get the first actual argument - file to read
# open the file
movl $5, %eax # open
movl $0, %ecx # read-only mode
int $0x80
# read the file
movl $0, %esi
# these 6 instructions read first character from inputfile.txt
movl %eax, %ebx # file_descriptor,
movl $3, %eax
movl $buff, %edi
leal (%esi,%edi,1), %ecx
movl buff_size, %edx
int $0x80
# these 6 instructions can't read the second character from inputfile.txt and I can't understand why.
movl $1, %esi
movl $3, %eax
movl $buff, %edi
leal (%esi,%edi,1), %ecx
movl buff_size, %edx
int $0x80
# open the file
popl %ebx # Get the second actual argument - file to write
movl $5, %eax # open
movl $2, %ecx # read-only mode
int $0x80
# write to STDOUT
movl %eax, %ebx # file_descriptor
movl $4, %eax
leal buff, %ecx
movl buff_size, %edx
int $0x80
# exit
movl $1, %eax
movl $0, %ebx
int $0x80
This piece of code read the first character from inputfile.txt successfully and it writes that character inside outputfile.txt...
Now I want to read and write the second character but it doesn't work as suggested in the comment I've written through the code.
FYI:
OS: Ubuntu 14 - 64 bit
Compiler: GAS
My inputfile.txt looks so: 4,3,55,15,8,9
Hi Guys I got some annoying problem ,so I try to write a code just to reverse small string sequential
I Already got this :
.section .data
string:
.ascii "AAAAAABBBBBB"
length:
.quad . -string #Dot = 'here'
.section .text
.globl _start #Make entry point visible to linker
_start:
movl $4, %eax #4=write
movl $1, %ebx #1=stdout
movl $string, %ecx
movl length, %edx
int $0x80 #Call Operating System
movl length,%edi #counter
shrl $1,%edi #half of string
movl $0,%ecx #start from index one
movl length,%edx #start from end
reverse:
movl string(,%ecx,1),%eax
movl string(,%edx,1),%ebx
movl %eax,string(,%edx,1)
movl %ebx,string(,%ecx,1)
inc %ecx
dec %edx
dec %edi
loop reverse #looping
movl $4, %eax #4=write
movl $1, %ebx #1=stdout
movl $string, %ecx
movl length, %edx
int $0x80 #Call Operating System
movl $0, %ebx #Make program return syscall exit status
movl $1, %eax #1=exit
int $0x80 #Call System Again
And it's not working correctly , cuz in gbd i get wrong values in registers after making
movl string(,%ecx,1),%eax
or the next steps I think there should be in %eax value for A letter but its doesn't any ideas ?
Working at 64arch but emulating in as --32 so its problem with my addressing i guess
You should be processing bytes not longs, so use movb with 8 bit registers (al and bl, for example). Also, the LOOP instruction uses ECX automatically, you probably meant JNZ there to repeat until EDI reaches zero.
simple upper-casifier loop infinitely
what's wrong with my code?
any advice?
my programming environment is linux, emacs, assembly, at&t syntax
.section .data
.section .bss
.lcomm buffer,1
.section .text
.global _start
_start:
movl %esp,%ebp
subl $8,%esp
#8(%ebp) is 2nd arg == input
#12(%ebp) is 3rd arg == output
#open,read,open,write,close
movl $5,%eax
movl 8(%ebp),%ebx
movl $0,%ecx
movl $0666,%edx
int $0x80
#%eax contains input's fd
#movl to first local var
movl %eax,-4(%ebp)
movl $5,%eax
movl 12(%ebp),%ebx
movl $03101,%ecx
movl $0666,%edx
int $0x80
#eax contains output's fd
#movl to second local var
movl %eax,-8(%ebp)
loop:
#read 1 byte from file 1st byte of data
movl $3,%eax
movl -4(%ebp),%ebx
movl $buffer,%ecx
movl $1,%edx
int $0x80
#buffer contains 1 byte of file
cmpb $0,buffer
je program_exit
pushl buffer
call convert #will return converted to %al
addl $4,%esp
movb %al,buffer
#write 1 byte from buffer to file
movl $1,%edx
movl $buffer,%ecx
movl -8(%ebp),%ebx
movl $4,%eax
int $0x80
jmp loop
program_exit:
movl buffer,%ebx
movl $1,%eax
int $0x80
.type convert,#function
convert:
pushl %ebp
movl %esp,%ebp
movb 8(%ebp),%al #1 byte data in the buffer
cmpb $'a',%al
jl convert_end
cmpb $'z',%al
jg convert_end
addb $32,%al #convert to upper
convert_end:
movl %ebp,%esp
popl %ebp
ret
Note that read(2) signals an end-of-file condition by returning 0. You're trying to find the end of the file by looking for an ascii NUL, which is very rare on Unix-derived systems. (If you want an easy way to make a terabyte-sized file, dd if=/dev/zero of=/tmp/huge bs=1048576 seek=1048576 count=1. The whole thing will be filled with ascii NUL characters. (Or the integer 0, however you want to interpret it.)
You need to modify your code to find the end of file by comparing the return value of the read(2) system call, not by looking at the data you receive into your buffer.