1

It is my first assembly program.
Can anyone please help to make it run successfully.
I am seeing below compilation error.

Why it do not recognize the ? and @data?
I am trying to swap two variables in assembly.

I am executing the following command

nasm -f elf swap.asm

But I get this error:

swap.asm:6: error: symbol `?' undefined
swap.asm:12: error: symbol `@data' undefined
swap.asm:15: error: invalid combination of opcode and operands
swap.asm:21: error: invalid combination of opcode and operands
swap.asm:22: error: invalid combination of opcode and operands

This is my code:

section .data
    C equ 15
    var1 db 12

section .bss
    var2 db ?

section .code
    global _start
    _start:

    mov ax, @data
    mov ds, ax

    mov var2, C

    ; swap var1 and var2

    mov al, var1
    mov bl, var2
    mov var2, al
    mov var1, bl

    ; now print the swapped values
    mov eax, 4  ;   4 = sys_write
    mov ebx, 1  ;   1 - std out FD
    mov ecx, var1
    mov edx, 8
    int 80h

    mov eax, 4  ;   4 = sys_write
    mov ebx, 1  ;   1 - std out FD
    mov ecx, var2
    mov edx, 8
    int 80h

    ; exit the program
    mov eax, 1  ; 1 = sys_exit
    mov ebx, 0
    int 80h
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Abhishek Sagar
  • 1,189
  • 4
  • 20
  • 44
  • 3
    You have a mixture of 16-bit code and 32-bit code and some of the code is MASM syntax and the rest is NASM. – Michael Petch Aug 01 '19 at 19:51
  • I think for below two instructions , operands are of different sizes. What should be the solution, shall i use cl instead of ecx ? mov ecx, var1 mov ecx, var2 – Abhishek Sagar Aug 01 '19 at 19:54

1 Answers1

4

This code indicates you have probably copy and pasted it from a MASM tutorial for 16-bit code:

mov ax, @data
mov ds, ax

On Linux the model is flat so this code is unnecessary and can be removed. Since you are compiling with NASM you have to place [] around memory references (unlike MASM) when you wish to access the data at a memory address. So code like:

mov al, var1

Should be:

mov al, [var1]

The NASM documentation has useful information on differences between NASM and MASM syntax in section 2.2 Quick Start for MASM Users. I have documented a number of other required changes in this revised code:

section .data
    C equ 15
    var1: db 12                ; NASM needs a colon after labels unlike MASM

section .bss
    var2: resb 1               ; NASM doesn't have '?'. Use RESB to allocate space
                               ; in BSS section. RESB 1 allocates 1 byte of space

section .text                  ; The code section in ELF is `.text` and not `.code`
    global _start
    _start:

    mov byte [var2], C         ; C doesn't need brackets because it was defined with EQU
                               ;     and is a constant (immediate) value.
                               ;     NASM can't determine the size of a constant
                               ;     nor does it know the size of data at var2
                               ;     so the BYTE directive is used on the memory operand.

    ; swap var1 and var2

    mov al, [var1]             ; Getting data from var1 - brackets needed
    mov bl, [var2]             ; Getting data from var2 - brackets needed
    mov [var2], al             ; Changing value at var2 - brackets needed
    mov [var1], bl             ; Changing value at var1 - brackets needed

    ; now print the swapped values
    mov eax, 4  ;   4 = sys_write
    mov ebx, 1  ;   1 - std out FD
    mov ecx, var1              ; No brackets because we want the address of var1
    mov edx, 1                 ; Print 1 byte
    int 80h

    mov eax, 4  ;   4 = sys_write
    mov ebx, 1  ;   1 - std out FD
    mov ecx, var2              ; No brackets because we want the address of var1

    mov edx, 1                 ; Print 1 byte
    int 80h

    ; exit the program
    mov eax, 1  ; 1 = sys_exit
    mov ebx, 0
    int 80h

If you run this code it may appear to not print what you expect. The SYS_write system call doesn't print integers - it prints strings. If you want to write the value 12 or 15 you would need to convert the number to a string and then pass the address of the string to SYS_Write system call. For a 32-bit solution that converts integer to string you can look at the answers to this related question. Another related answer by Peter Cordes has other useful information.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 1
    For that last part, there's working code for at [How do I print an integer in Assembly Level Programming without printf from the c library?](//stackoverflow.com/q/13166064) – Peter Cordes Aug 01 '19 at 20:09
  • 2
    Does `section .code` actually work here? [Assembly section .code and .text behave differently](https://stackoverflow.com/q/67084048) found that it didn't for x86-64 Linux, with that unknown section name being linked into a non-executable segment. Probably `ld` defaults changed, along with not putting `.rodata` into the text segment. Hmm, I just tested this code and it does `write` \17 and \f bytes with two separate syscalls, not segfaulting. – Peter Cordes Apr 14 '21 at 03:48
  • 2
    I think it `section .code` only works in 32-bit mode because of missing a PT_GNU_STACK note, leading to still getting exec-all (Or maybe that's just a side-effect of the execstack handling, with no PT_GNU_STACK you get exec-all in 32-bit executables instead of just exec-stack in x86-64: [Linux default behavior of executable .data section changed between 5.4 and 5.9?](https://stackoverflow.com/a/64837581)) – Peter Cordes Apr 14 '21 at 03:56