1

I am new to assembly and I'm trying to figure out how to print an array to the screen. I have an array called "Array" of size 10 elements.

This is the rest of my code:

section .data
    msg db "The array: "
    len equ $- msg
    Array   DB  '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'

section .text
global _start

_start:
    mov eax, 4
    mov ebx, 1

    mov ecx, msg            ;prints msg
    mov edx, len
    int 0x80

    jmp printArray          ;calls print array function


    jmp Exit                ;calls exit function

printArray:

    mov ebx, offset Array   ;address array with ebx
    mov ecx, 10             ; load counter with 10
    jmp Again               ; go to Again function
    ret

Again:
   mov eax, 4
   mov ebx, 1
   int 0x80
   inc ebx                 ;increments ebx to get next element in array
   dec ecx
                            ;;  compares the counter to 0
   cmp ecx, 0
   jnz Again

Exit:

    mov eax, 1
    mov ebx, 0
    int 0x80

It prints msg and constructs the array, but I need help looping through the array and printing the elements to the screen.

I hope a simple example like this can be useful for others who are starting out. Thanks for any help!

Alicia Sabatino
  • 57
  • 1
  • 2
  • 10
  • You're in an endless loop. Where do you check for the last item in `Array`? – SBF Nov 02 '17 at 15:05
  • @SBF if I add the lines “dec ecx” “cmp ecx, 0” and change Loop Again to “jnz Again” would that work? – Alicia Sabatino Nov 02 '17 at 15:12
  • `offset` is MASM syntax. The NASM equivalent is `mov ebx, Array`. It assembles to a `mov ebx, imm32`, not a load. (In MASM `mov ebx, Array` *is* a load. This is one of the major differences between MASM and NASM syntax. If you thought you needed `offset`, you've been reading a guide for the wrong syntax.) – Peter Cordes Nov 02 '17 at 15:12
  • Use a debugger to single-step your code and watch registers change. IDK why you did `mov ebx, 1` / `inc ebx`, but it's equivalent to `mov ebx, 2`. And yes, `dec ecx / jnz` is preferable to `loop`, but only because `loop` is slow. (Note that `dec` sets flags (other than CF) so you don't need a separate cmp.) – Peter Cordes Nov 02 '17 at 15:14
  • @PeterCordes ah yeah I just realized the textbook assigned to my class is MASM and I’m supposed to be doing it in NASM for whatever reason. – Alicia Sabatino Nov 02 '17 at 15:15
  • @PeterCordes I did mov and increment because I’m attempting to increment through the array and print the elements, but I’m not sure how and I’m doing something wrong. Can you tell me if my _start is ok ? Thank you – Alicia Sabatino Nov 02 '17 at 15:24
  • The differences between MASM and NASM are not huge, most of the people here helping with asm questions can recognize + switch to either without truly being expert on one of them, just by learning few crucial difference, so it's not hopeless, but I imagine it may be very confusing for somebody new to x86 assembly. In your place I would first search for few free NASM tutorials on Internet, try those examples out (cross checking with Intel documentation), learning to use nasm and debugger. Then I would read some article about NASM vs MASM syntax, then you may be slowly capable to read+write both. – Ped7g Nov 02 '17 at 15:34
  • the initial prompt and final exit looks ok, but the array can't be printed that simply, linux has no service for "print integer", you would have to first convert the integer to string in your shell encoding (probably utf8 which makes ASCII usable too = easy for beginners), and output the resulting string. You can for the sake of example and learning to traverse array put strings into array, like `array: dw ' 1', ' 2', ' 3', ...` and then keep fixing till you manage to print `" 1 2 3 ..."` (to practice debugger usage, which is absolutely essential tool to learn assembly) – Ped7g Nov 02 '17 at 15:42
  • @Ped7g so I changed the elements of the array to : ‘1’, ‘2’, etc but it still doesn’t print . It prints the initial msg, and that’s all. Do you know what I can do to get it to print an array of strings/characters ? Does my printArray function look ok? – Alicia Sabatino Nov 02 '17 at 15:46
  • re: MASM vs. NASM: You're using Linux (I can tell from the way you make system calls). The GNU assembler (`as` or gas) that gcc uses has a `.intel_syntax noprefix` mode that is a lot like MASM. But uses different directive (like .globl` instead of `global`) so it's probably more confusing and using it would probably make things more complicated for you, not less. Still, if you disassemble something with `objdump -drwC -Mintel a.out`, you'll get MASM-style disassembly using `offset`. That might help you sort out syntax differences between your book and your source code. – Peter Cordes Nov 02 '17 at 15:47
  • @PeterCordes ok thank you. I changed my goal to just printing an array of strings to the screen, because it’s simpler. Do you know what I need to fix for my printArray/Again function? – Alicia Sabatino Nov 02 '17 at 15:50
  • My point with `mov` / `inc` was that setting `ebx=2` every iteration of the loop is probably not what you wanted. Maybe you meant to do the `mov` outside the loop. (Or not at all, since `mov ebx, 1` overwrites the address you put in it.) Also, the first arg to `sys_write()` is a file descriptor (1 for stdout, 2 for stderr), not a pointer. So actually ebx=2 is useful, but only because what you were trying wasn't the right thing in the first place >.<. Anyway, use GDB and `strace` to see what you pass to system calls. See the bottom of https://stackoverflow.com/tags/x86/info for tips. – Peter Cordes Nov 02 '17 at 15:52
  • And BTW, `gdb` has an intel-syntax mode. Put `set disassembly-flavor intel` in your `.gdbinit`. – Peter Cordes Nov 02 '17 at 15:53
  • Oh hang on a minute. Your question title says 64-bit. You should be using a totally different way of making system calls, with different call numbers. [`eax=4` / `int 0x80` for the 32-bit ABI `sys_write` does work in 64-bit mode, but only with 32-bit pointers](https://stackoverflow.com/questions/46087730/what-happens-if-you-use-the-32-bit-int-0x80-linux-abi-in-64-bit-code). If you pass it a pointer to stack memory, it will fail. (returning `-EFAULT`, not crashing, so you just get no output unless you use `strace` or otherwise check the return value). – Peter Cordes Nov 02 '17 at 15:55
  • If you're trying to write 32-bit code, [build it with `nasm -felf32` and link with `gcc -m32 -nostdlib -static foo.o`](https://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit-system-gnu-toolchain). – Peter Cordes Nov 02 '17 at 15:56
  • what you need to fix for `printArray`/`Again`: You're looping the right number of times, I think, but you aren't passing sensible args to the system call or incrementing a pointer. – Peter Cordes Nov 02 '17 at 15:58
  • @PeterCordes could you post an answer with what the correct code would be? I can’t find how I would do it in my book – Alicia Sabatino Nov 02 '17 at 16:03
  • @AliciaSabatino: That's expected. Your current code has identical behaviour when built as 32 or 64-bit, it's just buggy, unfortunately. But in future, if you want to `push 0xa` and `write()` that newline from the stack, it would fail with `int 0x80` in 64-bit code, but work with `int 0x80` in 32-bit code (or with `syscall` in 64-bit code, with a different calling convention). If your textbook is using 32-bit code (e.g. if it ever uses `esp` instead of `rsp` for the stack pointer), then you should write 32-bit code and build it as 32-bit. Otherwise you should switch now to the 64-bit ABI. – Peter Cordes Nov 02 '17 at 16:06
  • Stackoverflow isn't a homework-answering / code-writing service, so I'm not going to write it for you. If you're stuck you should really ask your instructor for help with the basics. Hint: you should be calling (with `int 0x80`) [`write(1, pointer, 2)`](http://man7.org/linux/man-pages/man2/write.2.html) each time to print 2 characters to stdout. I'll leave it up to you to sort out whether you want to pad your array with spaces for the single-digit numbers, or whether you want to copy from the array into memory somewhere else and give `write` a pointer to that. My earlier link has an example – Peter Cordes Nov 02 '17 at 16:11
  • @PeterCordes this isn’t for homework. Just practicing, but thank you for your help. – Alicia Sabatino Nov 02 '17 at 16:12
  • See my edit to my previous comment. See this heavily-commented [Hello World for 32-bit x86 Linux](https://stackoverflow.com/a/39551489/224132) using `int 0x80` system calls for how to use `sys_write`. Actually you already know that, because you're printing `msg`. But the comments and text explaining *why* / *how* it works might be helpful. Notice that it takes the pointer in `ecx`, so don't use `ecx` as your loop counter. Use `edi` or something. – Peter Cordes Nov 02 '17 at 16:17
  • If you are taking a course in assembly, this is totally the kind of thing you could go to your instructor for help with, BTW. I'd recommend going to their office hours for help with this practice problem if you need help later. I expect most professors would be happy to go over your code with you, and that works much better in a 1-on-1 session in real-time than as a Stack Overflow question. I feel like a complete answer to this question would have to address every possible misunderstanding, because I don't know which misunderstandings led to the code you wrote. – Peter Cordes Nov 02 '17 at 16:21
  • Surely it should not print anything else, the code was missing important parts. But I was giving you just a hint to make the task reasonably complex (to avoid integer conversion when you are struggling even with access to memory and system calls usage). What you are struggling with has to be overcome if you want to get much further. At the moment it's not as important for you to get desired output on screen, as to find out some linux debugger which will work for you, learn to use it well enough; together with docs, find your mistakes, realize how CPU works, how it looks after each instruction. – Ped7g Nov 02 '17 at 18:10

0 Answers0