问题
When i type ld -m elf_i386 -o loop loop.asm, i get the error stated in the title, any idea what causes it? Sorry if the code looks bad, fairly new to assembly.
cr equ 13
lf equ 10
section .bss
numA resb 1
section .text
global _start:
mov [numA],byte 0
call loop1
jmp endend
loop1:
xor cx,cx
mov al, $numA
cmp cx, 0x0A
jle else
inc al
jmp end
else:
dec al
jmp end
end:
mov [$numA], al
inc cx
cmp cx,20
jle loop1
endend:
mov dl,$numA
mov ah,2
int 21h
回答1:
In NASM, $numA
is the same as numA
. A leading $ stops the assembler from considering it as a register name. Thus you can write mov eax, [$eax]
to load the eax
register from a symbol called eax
. (So you could link with C which used int eax = 123;
)
So mov [$numA], al
looks weird, but it's really just mov [numA], al
and isn't the source of the warning.
You're getting the warning from mov dl,$numA
which does a mov dl, imm8
of the low byte of the address.
The linker warns you because the address of numA
doesn't fit in 1 byte, so the r_386_8
relocation truncated the address.
The _8
tells you it's a relocation that asks the linker to fill in 8 bits. The r_386
tells you it's an i386 relocation as opposed to some type of r_x86_64 relocation (which could be absolute or RIP-relative), or a MIPS jump-target relocation (which would need to right-shift the offset by 2). Possibly related: Relocations in the System V gABI (generic ABI, for which the i386 SysV psABI is a "processor supplement").
回答2:
The fixed code with comments starting ;*
about what did I modify:
;* build commands used to test:
;* nasm -f elf32 -F dwarf -g loop.asm -l loop.lst -w+all
;* ld -m elf_i386 -o loop loop.o
cr equ 13
lf equ 10
section .bss
numA resb 1
section .text
global _start ;* global directive takes symbol name (without colon)
_start:
;* the actual label you defined as global, and want to start from.
;* set memory at numA address to byte zero
mov [numA],byte 0
;* try to call subroutine with loop
call loop1
jmp endend
loop1:
xor cx,cx ;* loop counter = 0
.real_loop:
;* you don't want to loop to "loop1" as that will reset CX!
mov al, [$numA] ; load AL with value from memory at numA address
;* in NASM you must use [] to indicate memory load/store
;* the mov al, $numA tried to put the memory address numA into AL
;* but memory address in x86-32 is 32 bit value, and AL is 8 bit only
;* and you didn't want address, but value any way.
cmp cx, 0x0A
jle .else
inc al
jmp .end
.else:
;* I modified all subroutine labels to be "local" starting with dot
;* i.e. ".else" is full label "loop1.else". This practice will allow
;* you to use also ".else" in different subroutines, while global
;* "else:" can be used only once per source file.
dec al
jmp .end
.end:
mov [$numA], al
inc cx
cmp cx,20
jle .real_loop ;* fix of loop jump (to not reset CX)
;* after CX will reach value 21, the CPU will continue here
ret ;* so added return from subroutine
endend:
;* call linux 32b sys_exit(numA value) to terminate
;* return value will be equal to zero-extended [numA] to 32bits
;* 8bit -1 = 0xFF -> return value is 255
movzx ebx,byte [$numA]
mov eax,1
int 80h
After running this:
nasm -f elf32 -F dwarf -g loop.asm -l loop.lst -w+all
ld -m elf_i386 -o loop loop.o
./loop ; echo $?
The output is expected:
255
来源:https://stackoverflow.com/questions/46939146/assembly-relocation-truncated-to-fit-r-x86-64-16-against-data