Linux Nasm Move a Value in Al Up to Ax

linux nasm move a value in AL up to AX

Just clear the ah register instead. The ax register consists of it's high and low part - ah:al

The same applies to bx (bh,bl) cx (ch,cl) and dx (dh,dl) registers

NASM adding value to register bug

I have an idea - I'm not sure if it is correct:

In your program you call "open" two times. One time you commented out the mov ecx, ...; the other time the ecx register has never been set at all:

openFileIn:
mov eax, 5
mov ebx, fileName
; <-- Here you are trusting Linux that ecx=0 on program start
; This is not guaranteed;
; it may change in future Linux versions!
mov edx, 0777
int 0x80
mov [fd_in], eax
ret

openFileOut:
mov eax, 5
mov ebx, outName
;mov ecx, 1 <-- why did you comment this out?
; Maybe "1" is not the correct value!
mov edx, 0777
int 0x80

In anoter line you write some address to the ecx register:

readFromFileIn:
mov eax, 3
mov ebx, [fd_in]
mov ecx, info ; <-- Here
mov edx, IMAGE_SIZE
int 0x80
ret

When you add instructions to your code the addresses of elements in the program may change - including the address of info.

I suspect that without the additional instruction the address of info is a valid parameter for the "open" system call by chance while after inserting the instruction the address is no longer a valid parameter for "open".

You could test this by running both variants of the program with the strace tool which shows you which system calls are called with wich parameters.

How can i copy an array in nasm x86 assembly for Linux, porting 16-bit DOS code?

The final code in nasm is this

section .text
global _start
cpu 386

_start:

MOV ESI, TABLE_A
MOV EDI, TABLE_B
MOV CX, 3

COPY_LOOP:
MOV AL, [ESI]
MOV [EDI], AL

INC SI
INC DI
LOOP COPY_LOOP

MOV AX,1
INT 80h

section .data
TABLE_A DB 10, 5, 1
TABLE_B DB 0, 0, 0

Move character from a string to a register in Assembly

The instruction mov al, msg2 would have gotten you the first byte of the string if this were MASM, but since you're using NASM you need to write the square brackets whenever you want to address memory.

mov al, [msg2]

When you wrote mov byte al, msg2, you asked NASM to put the address of msg2 in the AL register which is nearly always wrong since an offset address is supposed to be 16-bit! This is why you received the error:

obj output driver does not support one-byte relocations


Since your aim seems to be to get, one after the other, each character of the string, an instruction that just gets the first character can't help you very much. You need to put the address of the string in a register, read the memory where that register points at, and then increment the register. After doing something useful with AL, you test if the register points behind the last character of the string and if it doesn't you jump back to read the next character.

    mov     bx, msg2
Next:
mov al, [bx]
inc bx
...
cmp bx, msg2 + 10 ;Only if msg2 has precisely 10 characters
jb Next

A loop like this can only work if whatever code you replace the ... with, doesn't clobber the loop control register BX. If need be you can preserve BX yourself by adding push and pop instructions:

    mov     bx, msg2
Next:
mov al, [bx]
inc bx
push bx
...
pop bx
cmp bx, msg2 + 10 ;Only if msg2 has precisely 10 characters
jb Next

NASM Assembly - Get the Result of Multiplying Two Numbers in a Loop

This is an update, I fixed it. :)


;nasm 2.13.02

section .bss
result: resb 2
num1: resb 2
num2: resb 2
quotient: resb 2
remainder: resb 2

section .text
global _start

_start:

; setup registers
; mul -> AX = (AX * BX = DX BX)
;The multiplicand should be in the AX register,
;and the multiplier is a word in memory or another register.
;For example, for an instruction like MUL DX,
;you must store the multiplier in DX and the multiplicand in AX.

;The resultant product is a doubleword, which will need
;two registers. The high-order (leftmost) portion gets stored
;in DX and the lower-order (rightmost) portion gets stored
;in AX.

mov [num1], word 0x2A ;store 42 in eax
mov [num2], word 0x2B ;store 43 in edx (42*43=1806)

mov ax, [num1]
mov bx, [num2]
mul bx

mov [result], ax

call convert_values

;----------------------------------
; divide by ten
; div -> AX = (AX(dividendo) / BL(divisor) = AL (Quotient) AH (Remainder))
;The dividend is assumed to be in the AX register (16 bits).
;After division, the quotient goes to the AL register and
;the remainder goes to the AH register.
convert_values:
xor ax, ax ; clears AX register to `0`
mov ax, [result]
mov bl, 10 ; 10
div bl ; divide por 10

mov [quotient], al ; save the Quotient

call print_char ;print the latest character

mov ax, [quotient] ;move `Quotient` to AX register
test ax,ax ;Compares if AX register is equal to `0`
jz exit; ;if flag `ZF` is equal to `1` jump to `exit` label

mov [result], ax ;moves data from AX register to `result`

cmp ax,0 ;set flags based on ax value

jnz convert_values ;while al != 0 continue process
ret

; print a character
print_char:
mov [remainder], ah ; gets the Remainder
add [remainder], word '0'
mov eax,4 ; The system call for write (sys_write)
mov ebx,1 ; File descriptor 1 - standard output
mov ecx,remainder ; Put the offset of hello in ecx
mov edx,1 ; is a constant, so we don't need to say
int 80h ; Call the kernel
ret
;---------------------------------------------
exit:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 80h;

Unexpected results from division depending on whether I use EAX, AX, or AL

In this part of the code:

 46     sub byte [esi], 48      ; get value of digit
47 add edi, [esi] ; add to summ

It looks like the intent is to add a single digit to the sum, but that is not what actually happens. add edi, [esi] is implicitly the same thing as add edi, dword [esi], so really 4 characters are being added to the sum in an interesting way, though only the bottom one is intended, and only one of them is adjusted from an ASCII char to its numeric equivalent (by the way I don't quite understand why you change them back to ASCII characters, but that should be fine in principle, just redundant).

Using only the low byte of the result works, because the low byte is never "polluted" that way, the extraneous characters are added into the high bytes of eax.

How to fix: make sure you add only one char at the time. For example

movzx eax, byte [esi]
sub eax, 48
add edi, eax

If you prefer, you can merge the sub and add into lea:

movzx eax, byte [esi]
lea edi, [edi + eax - 48]

x86 nasm assembly, how to print multiplication result correctly?

The AAM instruction could be useful for cases where the result would have at most 2 digits. In your case 12 x 12 = 144, so that's a no-go.

The conversion loop that you use is almost correct, but you are mixing sizes in relation to the DIV instruction. If you give a byte-sized operand to DIV then the operation will divide AX by that byte and the remainder will be in AH. If you give a word-sized operand to DIV then the operation will divide DX:AX by that word and the remainder will be in DX.

Because you're writing 32-bit code, better also write the conversion using 32-bit registers.

Instead of using a digits counter, use a sentinel on the stack. No need to preserve ECX while displaying.

The display function expects a pointer in ECX. Just use the stackpointer for this and pop the value post-printing.

    mov   al, 12
mov bl, 12
mul bl ; answer in AX
movzx eax, ax

mov ebx, 10 ; Divisor constant
push ebx ; Sentinel
.a: xor edx, edx
div ebx ; Divide EDX:EAX with EBX, quotient EAX, remainder EDX
add edx, '0' ; Add '0' to make it into character
push edx
test eax, eax ; If EAX (the quotient) is not zero, loop again.
jnz .a

.b: mov eax, 4
mov ebx, 1
mov ecx, esp
mov edx, 1
int 0x80
pop eax
cmp dword [esp], 10 ; Is it the sentinel ?
jne .b ; No, it's a digit
pop eax ; Remove sentinel

Although not 32-code, Displaying numbers with DOS has more info about converting numbers into text.

How to mov values in eax register, ah and al left by 2 bytes? x86 Assembly

If you can't use shl eax, 16 like a normal person, your other options include the following:

  • add eax,eax repeated 16 times (yuck, slow), in a loop partially unrolled, or fully unrolled.
  • store / reload at an offset: also slow, but only for latency (store-forwarding stall). Throughput can be ok, while latency is pretty close to the same 16 cycles as the 16x add way on a typical modern x86.
    sub  esp, 16             ; reserve some stack space.

...
mov [esp+2], ax ; 2 byte store
mov eax, [esp] ; 4-byte reload with previous AX in the top half

mov ah, ... ; overwrite whatever garbage in the low 2 bytes
mov al, ...

x86 is little-endian, so load/store of EAX to addr loads/stores AL to that same addr, and AH to addr+1., with the high 2 bytes coming from addr+2 and +3.

Reading EAX after writing AH and AL will also force the CPU to merge partial registers if it renamed AH (and maybe AL) separately from the full EAX, but clearly if you're restricting yourself to only a tiny subset of the ISA then high performance isn't your top goal. (See Why doesn't GCC use partial registers? and How exactly do partial registers on Haswell/Skylake perform? Writing AL seems to have a false dependency on RAX, and AH is inconsistent for more details.)

For the store-forwarding stall part, see Can modern x86 implementations store-forward from more than one prior store?


Depending how much you're doing with the new low part (the new AH and AL), you might actually do them in a separate register (like DH and DL), so out-of-order exec can get started on that work, without a false dependency on the store-forwarding reload, especially on CPUs that don't rename AL (or even AH) separately from EAX. (i.e. CPUs that aren't Intel P6 family, like crusty old Nehalem).

So you'd do

    mov  [esp+2], ax         ; 2 byte store
mov eax, [esp] ; 4-byte reload with previous AX in the top half

mov dl, ...
mov dh, ...
... more computation with these two

mov ax, dx ; replace low 2 bytes of EAX

mov ax,dx might need to wait for the old EAX value to be "ready", i.e. for the reload to complete, so it can merge into it as part of running that instruction. (On Intel Sandybridge-family, and on all non-Intel CPUs.) So this lets the computations on DL/DH overlap with the store-forwarding latency.

Just to be clear, all this discussion about tradeoffs is about performance, not correctness; all ways I've shown here are fully correct. (unless I made a mistake :P)

Assembly, NASM; how is the information in 32 bit registers divided among sub registers?

AL will have the first t, AH will have e, AX will have et (te depending on how you consider the lower character and higher character). It's been likely 15-18 years since I've touched assembler, but that's what I remember anyhow.

szString will look like this in memory:

t    e    s    t
0x74 0x65 0x73 0x74

mov eax,[szString]

will have:
AL - 0x74
AH - 0x65
AX - 0x6574
EAX - 0x74736574

Primitive ASCII art:

[74][65][73][74]
[-----EAX------]
[--AX--]
[AL][AH]


Related Topics



Leave a reply



Submit