NASM output data register value

The new guy is here, and I already have a question.

Am I fitting the sample code used in Jeff Duntemann builds and I want to print the integer value stored in the data register to the terminal?

What the following code does is that it prints the lines in order, pushes the value in ECX in order, but when it moves on to the following:

pop ecx mov eax,4 mov ebx,1 mov edx, ecx int 80h 

It does not display edx content on the terminal, although I think I said it with mov eax, 4, etc.

Anyone who can give me "pointers" (pun intended)?

Code for reference (as amended on 06/17/2012):

 SECTION .data submessage: db "I am subtracting 5 from 10!", 10 msglen: equ $-submessage ansmsg: db "Answer is:", 10 msglen2: equ $-ansmsg EOL: db 10 SECTION .bss msg: resd 2 ; reserve space for 2 dwords SECTION .text global _start _start: nop ;Displays test on shell mov eax,4 ;print to terminal mov ebx,1 mov ecx, submessage mov edx, msglen int 80h ;"I am subtracting 5 from 10!" mov eax,4 ;print to terminal mov ebx,1 mov ecx, ansmsg mov edx, msglen2 int 80h ;"Answer is..." ;Subtraction operation below: mov edx, 10 sub edx, 5 mov [msg], edx ; store 5 in msg ; now we need to print msg to terminal mov eax, 4 ;print to terminal mov ebx, 1 mov dword [msg+1], 0xa ;helps prints something out! ;Encountered problem here= prints out 'Answe' instead of integer '5' push dword 2 ; store size of msg push dword [msg] ; push to stack contents of msg int 80h add esp, 3 ;clean stack (2 push calls *4) int 80h ; I like labels :) sys_exit: mov eax,1 ;exit status mov ebx,0 int 80h nop 

PS- If my line indentation sucks, I would like to know how I can improve it; The IMHO training assembly becomes more attractive after you move on to the initial hump training :)

+4
source share
2 answers

Firstly, thanks for the question - it motivated me to study in the 80s, which I did not know before.

What does your program do in its current form? Does anything print? If I do this correctly in my head, I expect him to print the first message and then fail. Due to buffering, it may not even show the first message until the alleged failure.

int 80h / eax = 4 displays the write () function. Run "man 2 write" to get the full documentation. Function Prototype:

 ssize_t write(int fd, const void *buf, size_t count); 

So eax = 4, ebx = fd, ecx = buf, edx = count. If you want to be more pedantic with your code comments, "mov eax, 4" means "write a line to a file", while "mov ebx, 1" means "indicate file No. 1, which is displayed in STDOUT (terminal)" ,.

I expect the first call to type 80h to print something. The second call to int 80h is suspicious. At this point, eax and ebx do not change. However, edx also does not change and contains the line length of the first line. More problematic is that you insert the value 5 into ecx. ecx contains a pointer to the string to be written, not the value to be written. Therefore, when you put 5 there and cause an interrupt, int will try to print a line starting at address 0x00000005. This almost certainly causes segfault (crash).

Also, if I read 8080 documents correctly, the push / pop stack operations in your example are of no relevance.

Printing a number as a string is a bit of a challenge in ASM. You need to convert the number to a string, and then you can print it with int 80h. Here you can cheat if you just want to print one number:

  • in the .data section declare a new byte named int2char: 'int2char: db 0'
  • after subtracting 5 from ecx, convert the digit to ASCII by adding 48 (this will give you β€œ5” instead of 5)
  • save ecx to int2char
  • move the int2char address to ecx
  • set edx to 1 since you only want to print 1 char

Converting numbers with more than one digit will be left as an exercise for you as soon as you do.

Good luck

+1
source

I think push messages are relevant. Here is another example of a hello world program.

 section .text global _start ;must be declared for linker (ld) _syscall: int 0x80 ;system call ret _start: ;tell linker entry point push dword len ;message length push dword msg ;message to write push dword 1 ;file descriptor (stdout) mov eax,0x4 ;system call number (sys_write) call _syscall ;call kernel ;the alternate way to call kernel: ;push eax ;call 7:0 add esp,12 ;clean stack (3 arguments * 4) push dword 0 ;exit code mov eax,0x1 ;system call number (sys_exit) call _syscall ;call kernel ;we do not return from sys_exit, ;there no need to clean stack section .data msg db "Hello, world!",0xa ;our dear string len equ $ - msg ;length of our dear string 

Now I have not written the code above, it came from here:

http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#helloworld

So you can see that this author can push values ​​onto the stack and call the kernel program, which will take parameters from the stack. This actually makes more sense to me, as I thought how parameters were passed to c-functions. Passing parameters through specific registers does not make sense. What if the method has 30 parameters, how would you pass this through registers?

In any case, I compiled the above code, linked it and ran it on my macbook pro, and it worked fine.

In any case, as good as in the above example, it’s not enough to teach you. Here, I think, is the best example of how you will print an arbitrary value from a register.

So what I want is not a predefined string, but a real programming construct; variable.

Easy enough, you can define a 32-bit variable by doing the following:

 section .bss msg: resd 2 

This gives me a variable (or memory location) called msg that I can store. By declaring it with resd, I determine the number of double words that I want to reserve. The double word is 32 bits, so I declare that I want to reserve 2 double words. Why 2? I will tell you in a moment.

So far so good.

Now all I have to do is move the value to this memory location and follow the example from hello, world, right? So I coded this:

 section .text global _start ;must be declared for linker (ld) _syscall: int 0x80 ;system call ret _start: ;tell linker entry point mov dword [msg], 'h' ;move the letter h into my memory location mov dword [msg+1], 0xa ;this is so important, but other author gloss over it ; the line terminator is essential in order to ; print something out push dword 2 ;message length push dword msg ;message to write push dword 1 ;file descriptor (stdout) mov eax,0x4 ;system call number (sys_write) call _syscall ;call kernel ;the alternate way to call kernel: ;push eax ;call 7:0 add esp,12 ;clean stack (3 arguments * 4) push dword 0 ;exit code mov eax,0x1 ;system call number (sys_exit) call _syscall ;call kernel ;we do not return from sys_exit, ;there no need to clean stack section .bss msg: resd 1 

So not too much has changed. I added a .bss section which is for uninitialized data. Much more useful than static strings. We move the static value (letter h) to the msg memory location, but you can move the case as easily as this

 mov [msg], eax 

The next line is so important, but every author of "hello world" just hides it. That 0xa is the line terminator that is required, or WILL_NOT, displays your values. It made me go crazy, trying to figure out why none of this would work. You NEED this terminator. This is why we need to define our variable in order to have two values ​​instead of one. We need to save this terminator.

The rest is simple, flip the parameters onto the stack and call the kernel. You now have an example of how to print some arbitrary data from the actual location of the variables. Enjoy it!

+1
source

Source: https://habr.com/ru/post/1416445/


All Articles