2

I copied the sample program on assembler and compiled it using gcc, but I got the following output:

gcc hello.s -o hello1

/usr/bin/ld: /tmp/ccPs5dcq.o: relocation R_X86_64_32 against `.data' can not be used when making a PIE object; recompile with -fPIE

/usr/bin/ld: final link failed: nonrepresentable section on output

collect2: error: ld returned 1 exit status

Code:

.data
hello_str:
        .string "Hello, world!\n"
        .set hello_str_length, . - hello_str - 1
.text 
.globl  main
.type   main, @function       
main:
        movl    $4, %eax      
        movl    $1, %ebx      
        movl    $hello_str, %ecx  
        movl    $hello_str_length, %edx 
        int     $0x80         
        movl    $1, %eax      
        movl    $0, %ebx      
        int     $0x80         
        .size   main, . - main    

What am i doing wrong?

P.S. I'm absolutely beginner in assembler, just trying to parse the example

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    Try to compile with `-fno-pie`. Let me see if I can find a good duplicate for this one. – fuz Jan 09 '20 at 12:02
  • @fuz thanks, it works, what does it mean? – Galina_1960 Jan 09 '20 at 12:08
  • 1
    The instruction `movl $hello_str, %ecx` needs to know the address of `hello_str` at link time. This is not the case when creating PIE (position independent) executables, so the linker shouts at you. It is possible to write the same code in a position-independent way, but in 32 bit code, it's a lot more difficult to do, so it's best to ignore this for now. Also, given that you write 32 bit code, you need to assemble and link with `-m32` or weird problems are going to occur. – fuz Jan 09 '20 at 12:24
  • @fuz: Note the `R_X86_64_32` relocation: the problem is no support for *32-bit* absolute fixups in 64-bit mode. With `-m32` the dynamic linker can fixup a 32-bit absolute to hold any pointer in the whole address space, so it is supported. The error message is a duplicate of [32-bit absolute addresses no longer allowed in x86-64 Linux?](//stackoverflow.com/q/43367427), except that the real fix is `-m32` (and probably also `-no-pie` is a good idea even if not required). – Peter Cordes Jan 09 '20 at 16:20
  • If you were compiling as 64-bit code [What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](//stackoverflow.com/q/46087730) would also apply. – Peter Cordes Jan 09 '20 at 16:22

1 Answers1

2

I had the same issues as OP with gcc and his code, but I can assemble this with the default GNU as with:

as hello.s -o hello.out && ld hello.out -e main -o hello && ./hello

source: https://askubuntu.com/questions/1064619/how-can-i-compile-run-assembly-in-ubuntu-18-04

Another hello world that works is the first example from here.


A possibly a better hello world (thanks to Peter Cordes) that avoids all of this by using lea (still magic to me):

.text

.global main

main:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        lea     message(%rip),%rsi      # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall                         # invoke operating system to do the write

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # we want return code 0
        syscall                         # invoke operating system to exit

.section .rodata
message:
        .ascii  "Hello, world\n"

Then you can assemble without errors with:

gcc hello.s -o hello

And run with ./hello

Perhaps worth reading is the list of linux syscalls to see why and what you need to write to get things shown on the terminal.

user27221
  • 334
  • 3
  • 16
  • 2
    You're still using 32-bit absolute addresses, so that *only* works in non-PIE executables. So unlike the comments, that could only be built with `gcc -nostdlib -static foo.s` (or `-no-pie`). Using `lea message(%rip), %rsi` is the same size as sign-extending `mov $imm32, %reg64`, and works everywhere. [How to load address of function or label into register](https://stackoverflow.com/q/57212012). Also, generally you'd want to put your message in `.section .rodata` – Peter Cordes Jun 23 '21 at 00:36
  • I made the changes you suggested and it work just fine, thank you! – user27221 Jun 23 '21 at 12:12
  • 2
    Re: the first part of this answer: it's generally recommended to use `_start` as the name for the ELF entry point, not `main`. i.e. instead of using `-e main` which is just confusing for everyone, change the source to call it `_start`. This is safe in this case because it uses an exit system call, not trying to return. (And it doesn't need any libc functions either, so you could just link it into a static executable with no other code at all using `ld`.) – Peter Cordes Jun 23 '21 at 13:52