0

Here is the code

//hello.c
char* str = "Hello world!\n";

void print()
{
    asm(
        "mov $13, %%rdx \n\t"
        "mov %0,  %%rcx \n\t"
        "mov $0,  %%rbx \n\t"
        "mov $4,  %%rax \n\t"
        "int $0x80       \n\t"
        ::"r"(str):"rdx","rcx","rbx");
}

void exit()
{
    asm(
        "mov $42, %rbx \n\t"
        "mov $1,  %rax \n\t"
        "int $0x80      \n\t"
    );
}

void hello()
{
    print();
    exit();
}

And here is the link script hello.lds

ENTRY(hello)

SECTIONS
{
    . = 0X08048000 + SIZEOF_HEADERS;
    
    tinytext : {*(.text) *(.data) *(.rodata)}
    
    /DISCARD/ : {*(.comment)}
}

I use the following command to compile and build an ELF file, and I want to combine .text, .data and .rodata to one .tinytext, what's more, I want to discard .comment.

gcc -c -fno-builtin hello.c
ld -static -T hello.lds -o hello hello.o

But the thing is that this can not work, when using objdump or readelf, I find the .text .data and .rodata still exist. What's more, the ELF file size enlarged from 1.6KB to 296KB(What I intended for is that the size may be less than 1KB).

Is there any problem of my operation?

And when I change the addr from 0x08048000 to 0x00000000, I find the size decrease from 296KB to a relatively small size like 1.1KB, can anyone explain it?

Thanks for any help.

tyChen
  • 1,404
  • 8
  • 27
  • I don't see `.text`, `.data` or `.rodata` in the result. – Jester Jan 08 '21 at 16:17
  • 1
    Note that `0x8048000` is a common base in 32 bit programs, not 64 bit. Looks like the 64 bit linker forces bigger alignment, at least by default. PS: your inline assembly is broken, but that wasn't the question :) – Jester Jan 08 '21 at 16:43
  • @Jester Thanks for your reply. The inline assembly works well in my VMware Ubuntu 16.04, 64bit environment. So do you know the common base in 64 bit program? – tyChen Jan 08 '21 at 17:28
  • 1
    Just because something happens to work doesn't mean it's correct. You can check any default linker script for the common base addresses, but it is usually `0x400000`. – Jester Jan 08 '21 at 18:06
  • Your inline asm forgot to tell the compiler that it clobbers R8..R11, as well as RAX. ([Don't use `int $0x80` in 64-bit code](https://stackoverflow.com/questions/46087730/what-happens-if-you-use-the-32-bit-int-0x80-linux-abi-in-64-bit-code).) You also forgot a `"memory"` clobber even though your asm reads memory without telling the compiler about it. (But fortunately that memory is a string literal so it doesn't get optimized away.) [How to invoke a system call via syscall or sysenter in inline assembly?](https://stackoverflow.com/q/9506353) a write `write()` that's safe and doesn't suck. – Peter Cordes Jan 09 '21 at 03:18
  • @Peter Cordes Thanks for your reply, I'll read the link and change my code to make it better. – tyChen Jan 09 '21 at 03:57

1 Answers1

1

After the help from Jester and Peter Cordes, I solve the problem. This problem comes from the wrong use of lds. In 64bit program, the general base address is not 0x08048000 but 0x400000. Changing that address, I successfully decrease the size of ELF file to 700 bytes and the result of objdump is just what I want to have.

tyChen
  • 1,404
  • 8
  • 27