1

i have a question about 32-bit addressing size instead of 64-bit addressing size in 64-bit Mode

func:
    movzx    eax, al  ; instead of movzx rax, al
    mov      eax, DWORD [4 * eax + .data]  ; instead of mov rax, QWORD [8 * rax + .data]
    ret

    .data:
         DD .DATA1     ; instead of DQ
         DD .DATA2     ; instead of DQ
         DD .DATA3     ; instead of DQ
         DD .DATA4     ; instead of DQ

.DATA1     DB 'HEY1', 0x00
.DATA2     DB 'HEY2', 0x00
.DATA3     DB 'HEY3', 0x00
.DATA4     DB 'HEY4', 0x00

is it a safe way in 64-bit ? because i think in 64-bit and addressing like this, there is no problem ! (i do this because .data)

i think .data and each item address is fit for 32-Bit registers if the program size (executable) be less than about 100 Mb which always is !

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
ELHASKSERVERS
  • 195
  • 1
  • 10
  • You are reading from .data, which is just a pointer to memory. What comes after is your own choice. Also, you'll have to know on reading whether you need to read the data as 32 bit or 64 bit values (or even as bytes, as the contents seem to be ascii strings). – PMF Dec 05 '19 at 09:33
  • You can safely cheat, by using a 32-bit offset from a 64-bit base address, like "`myTable: dd .DATA1- myTable, DATA2-myTable, ...`" and "`movzx ecx, al`, `mov ecx,dword [myTable + ecx*4]`, `mov rax,myTable`, `add rax, rcx`". – Brendan Dec 05 '19 at 12:18

1 Answers1

3

This would be unsafe on x86-64 MacOS for example, or in a Linux PIE executable. Program size isn't the only factor because it's not loaded starting at virtual address 0. The first byte of your program may be at something like 0x555555555000, so truncating an address to 32 bit would break you code no matter how small your program is.

(You'd get an invalid relocation linker error from using [.data + rax*4] in that case, though, just from using .data as an absolute disp32. 32-bit absolute addresses no longer allowed in x86-64 Linux?). But if you'd used [edi + eax*4] with a valid pointer in RDI, you could write code that would assemble but crash in a PIE executable or a MacOS executable.)

But yes, the default non-PIE Linux code model places all code and static data in the low 2GiB of virtual address space so 32-bit absolute sign- or zero-extended numbers can represent addresses.


Your data in memory is the same size regardless of how you address it, so your alternatives are

 movzx    eax, al
 mov      eax, DWORD [4 * eax + table_of_32bit_pointers]  ; pointless
 mov      eax, DWORD [4 * rax + table_of_32bit_pointers]  ; good

 ; RAX holds a zero-extended pointer.

mov rax, QWORD [8 * rax + .data] would load 8 bytes from a different location. You're still mixing up address size and operand-size.

Using compact 32-bit pointers in memory doesn't mean you have to use 32-bit address size when you load them.

Like I explained in your previous question there's no reason to use 32-bit address-size after zero-extending an index to 64-bit with movzx eax, al. (BTW, prefer movzx ecx, al; mov-elimination only works between different registers.)

BTW, if your strings are all the same length, or you can pad them to fixed length cheaply, you don't need a table of pointers. You can instead just compute the address from the start of the first string + scaled index. e.g. p = .DATA1 + idx*5 in this case, where your strings are 5 bytes long each.

lea  eax, [.DATA1 + RAX + RAX*4]    ; 4+1 = 5
; eax points at the selected 5-byte string buffer

Also, don't use .data as a symbol name. It's the name of a section so that's going to get confusing.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • thank you ... so you telling me that using 'DQ' instead of 'DD' is a safe way and it's better to use what i wrote 'instread' in source code Comment ? (mov rax, QWORD [8 * rax + .data]) – ELHASKSERVERS Dec 05 '19 at 09:47
  • @ELHASKSERVERS: no, I'm saying that if you're making an executable where you can use `[data + rax*4]` safely, you can store static addresses in 4 byte array elements and load it with zero-extension instead of having to do 64-bit loads. – Peter Cordes Dec 05 '19 at 09:50
  • like this eax, DWORD [4 * rax + table_of_32bit_pointers] ? but still it's a problem for MacOS or PIE ... true ? – ELHASKSERVERS Dec 05 '19 at 10:15
  • @ELHASKSERVERS: Yes to both. You're on Linux, right? You could link with `ld -pie` or `gcc -pie -nostdlib` (or even `gcc -static-pie -nostdlib`) and try it yourself. The one case where `[disp32 + rax*4]` works but `[disp32 + eax*4]` doesn't is a high-half kernel, where your static addresses are in the top 2GiB of address space so 32-bit sign-extended works but zero-extended doesn't. (32-bit address size zero-extends to 64.) Of course in that case you'd have to load pointers with `movsxd rax, [table + rax*4]` to sign-extend the data from memory explicitly. – Peter Cordes Dec 05 '19 at 10:19
  • im creating a small library for my self which can be linux or win and also can be PIE or ELF or MZ COFF or ... ! so i choosed this way : movzx rax, al mov rax, QWORD [8 * rax + .DATA] and my table is DQ .DATA0 ..... is it good now ? – ELHASKSERVERS Dec 05 '19 at 10:31
  • @ELHASKSERVERS: Like I said, use `movzx ecx, al` so mov-elimination works, not within RAX. And writing a 32-bit register implicitly zero-extends into the full 64-bit register. Or better, take your arg as `ptrdiff_t` or `size_t` so the caller will pass it already extended to 64-bit. But then yes, a table of DQ pointers and a 64-bit load are what you want if you need to link into PIC / PIE code, or Windows LARGEADDRESSAWARE=yes. – Peter Cordes Dec 05 '19 at 10:43
  • about movzx ecx, al if there is anything in the higher 32-bit of ecx (rcx) there will be a problem ! or i heard if we move something in the lower 32-bit, it will changes the higher 32-bit to zero .. is it true ? – ELHASKSERVERS Dec 05 '19 at 10:47
  • @ELHASKSERVERS: Yes. How many times to I have to tell you that writing a 32-bit register zero-extends to the full register? That was literally the next sentence in my last comment. [Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?](//stackoverflow.com/q/11177137) And you probably didn't read [The advantages of using 32bit registers/instructions in x86-64](//stackoverflow.com/q/38303333) that I linked in my answer to your previous question. – Peter Cordes Dec 05 '19 at 10:49