Write file from kernel land - c
I would like to write into a log file from the kernel space. I can create, open & close file (/var/log/my_kern_module.log) but if I try to write something into, my module crash... So I know read/write file from kernel space is bad, but I must do it in this module. Do you have any suggestion to help me ? thx
Here you can find the code who perform write on my kernel module. It code run into a thread (kthread)
mutex_lock(&gl_mtx_writelog);
printk(KERN_EMERG "Readed : %s\n", buffer);
fd = filp_open("/var/log/my_kern_module.log", O_CREAT | O_WRONLY | O_APPEND, S_IRWXU);
if (!IS_ERR (fd)) {
fs = get_fs();
set_fs(KERNEL_DS);
do_sync_write(fd, buffer, readed, 0);
set_fs(fs);
filp_close(fd, NULL);
}
mutex_unlock(&gl_mtx_writelog);
so, i've tried to use fd->f_op->write(...), but module crash too.
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c10df83a>] do_sync_write+0x6a/0xe0
*pde = 00000000
Oops: 0000 [#1] SMP
last sysfs file: /sys/module/snd_mixer_oss/initstate
Modules linked in: trigger_server snd_seq_dummy snd_seq_oss snd_seq_midi_event s nd_seq snd_seq_device snd_pcm_oss snd_mixer_oss ipv6 pcmcia pcmcia_core agpgart lp fuse ppdev snd_intel8x0 snd_ac97_codec ac97_bus thermal i2c_piix4 snd_pcm the rmal_sys i2c_core snd_timer e1000 parport_pc parport snd rtc_cmos rtc_core rtc_l ib joydev psmouse soundcore snd_page_alloc evdev usbhid serio_raw hid hwmon ac b utton sg [last unloaded: pcmcia_core]
Pid: 2468, comm: kthread_cli Not tainted 2.6.33.4-smp #1 /VirtualBox
EIP: 0060:[<c10df83a>] EFLAGS: 00010287 CPU: 0
EIP is at do_sync_write+0x6a/0xe0
EAX: f6434000 EBX: 00000000 ECX: 00000200 EDX: f5c26400
ESI: f653ca80 EDI: f5cf1f14 EBP: f5cf1f98 ESP: f5cf1f0c
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Process kthread_cli (pid: 2468, ti=f5cf0000 task=f6434000 task.ti=f5cf0000)
Stack:
c103de14 00000441 00000000 00000442 00000000 00000001 ffffffff f653ca80
<0> 00000000 00000000 00000000 00000000 f6434000 00000000 00000000 c10384a6
<0> 0000052b 00000000 0000052b ffffffff f5c26400 00000400 f5cf1f98 00000442
Call Trace:
[<c103de14>] ? vprintk+0x184/0x3d0
[<c10384a6>] ? try_to_wake_up+0x226/0x350
[<f887b226>] ? thread_client+0x106/0x130 [trigger_server]
[<f887b120>] ? thread_client+0x0/0x130 [trigger_server]
[<c1058cf4>] ? kthread+0x74/0x80
[<c1058c80>] ? kthread+0x0/0x80
[<c10035be>] ? kernel_thread_helper+0x6/0x10
Code: 94 00 00 00 00 c7 45 98 00 00 00 00 c7 45 9c 00 00 00 00 c7 45 a0 00 00 00 00 89 45 a4 c7 45 a8 00 00 00 00 c7 45 ac 00 00 00 00 <8b> 03 8b 53 04 89 4d c8 89 45 b0 89 55 b4 eb 13 8d b6 00 00 00
EIP: [<c10df83a>] do_sync_write+0x6a/0xe0 SS:ESP 0068:f5cf1f0c
CR2: 0000000000000000
---[ end trace 32d03f08f128f335 ]---
One obvious problem is that the 4th parameter to do_sync_write() is a pointer to where the file offset is stored (so it can be updated). You are passing 0 which might explain the NULL pointer problem. Could try:
loff_t ppos = 0;
do_sync_write(fd, buffer, readed, &ppos);
Equivalent methods to do what you need are listed here.
Why writing files from the kernel is bad ?
This comes up all the time on LKML, and the answer is always "don't do it". There is always a better way.
Related
I compile a nearly empty .c file. What's in its .text section? [duplicate]
This question already has answers here: GCC: Empty program == 23202 bytes? (10 answers) Closed 1 year ago. I write a nothing.c, which is just one line as follows int main(){} Then I compile it using command gcc nothing.c -o nothing Here's what I get using command readelf -x .text nothing Hex dump of section '.text': 0x00001040 f30f1efa 31ed4989 d15e4889 e24883e4 ....1.I..^H..H.. 0x00001050 f050544c 8d055601 0000488d 0ddf0000 .PTL..V...H..... 0x00001060 00488d3d c1000000 ff15722f 0000f490 .H.=......r/.... 0x00001070 488d3d99 2f000048 8d05922f 00004839 H.=./..H.../..H9 0x00001080 f8741548 8b054e2f 00004885 c07409ff .t.H..N/..H..t.. 0x00001090 e00f1f80 00000000 c30f1f80 00000000 ................ 0x000010a0 488d3d69 2f000048 8d35622f 00004829 H.=i/..H.5b/..H) 0x000010b0 fe4889f0 48c1ee3f 48c1f803 4801c648 .H..H..?H...H..H 0x000010c0 d1fe7414 488b0525 2f000048 85c07408 ..t.H..%/..H..t. 0x000010d0 ffe0660f 1f440000 c30f1f80 00000000 ..f..D.......... 0x000010e0 f30f1efa 803d252f 00000075 2b554883 .....=%/...u+UH. 0x000010f0 3d022f00 00004889 e5740c48 8b3d062f =./...H..t.H.=./ 0x00001100 0000e829 ffffffe8 64ffffff c605fd2e ...)....d....... 0x00001110 0000015d c30f1f00 c30f1f80 00000000 ...]............ 0x00001120 f30f1efa e977ffff fff30f1e fa554889 .....w.......UH. 0x00001130 e5b80000 00005dc3 0f1f8400 00000000 ......]......... 0x00001140 f30f1efa 41574c8d 3da32c00 00415649 ....AWL.=.,..AVI 0x00001150 89d64155 4989f541 544189fc 55488d2d ..AUI..ATA..UH.- 0x00001160 942c0000 534c29fd 4883ec08 e88ffeff .,..SL).H....... 0x00001170 ff48c1fd 03741f31 db0f1f80 00000000 .H...t.1........ 0x00001180 4c89f24c 89ee4489 e741ff14 df4883c3 L..L..D..A...H.. 0x00001190 014839dd 75ea4883 c4085b5d 415c415d .H9.u.H...[]A\A] 0x000011a0 415e415f c366662e 0f1f8400 00000000 A^A_.ff......... 0x000011b0 f30f1efa c3 ..... So what does it do?
So what does it do? You can see what it does: objdump -d nothing Disassembly of section .text: 0000000000001040 <_start>: 1040: 31 ed xor %ebp,%ebp 1042: 49 89 d1 mov %rdx,%r9 1045: 5e pop %rsi 1046: 48 89 e2 mov %rsp,%rdx 1049: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 104d: 50 push %rax 104e: 54 push %rsp 104f: 4c 8d 05 3a 01 00 00 lea 0x13a(%rip),%r8 # 1190 <__libc_csu_fini> 1056: 48 8d 0d d3 00 00 00 lea 0xd3(%rip),%rcx # 1130 <__libc_csu_init> 105d: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 1125 <main> 1064: ff 15 76 2f 00 00 call *0x2f76(%rip) # 3fe0 <__libc_start_main#GLIBC_2.2.5> 106a: f4 hlt 106b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 0000000000001070 <deregister_tm_clones>: 1070: 48 8d 3d b1 2f 00 00 lea 0x2fb1(%rip),%rdi # 4028 <__TMC_END__> 1077: 48 8d 05 aa 2f 00 00 lea 0x2faa(%rip),%rax # 4028 <__TMC_END__> ... etc.
The compiler injects info when you are compiling the source code. This highly depends on the operating system and the compiler you are using. For example, on a macOS, the compiler injects the so-called 'unwind info' which does something with unwinding the stack when there is an exception. To get to know what the compiler injects in your .text file besides the empty main, you should generate a .map file in which you will see clearly what's going on. The next question will be why the compiler injects this extra section? To generate a .map file use the following command: gcc -Wl,-map,nothing.map nothing.c -o nothing
U-boot: how to check if tftp command successfully loaded image into ram?
I load a rootfs image into RAM via u-boot tftp and flash it to the device flash storage. This is currently done manually, but now I want to do it automatically via a u-boot script: tftp ${rootfs_image}; mmc write ${loadaddr} ${blk} ${cnt} However, when it looks for an image from the tftp server with the u-boot tftp ${rootfs_image} command and it DOESN'T find the image, I don't want to run the mmc write part of the script. How do I check if the tftp command successfully downloaded the image into RAM?
Using the TFTP protocol does not ensure that the integrity of the transferred data will be preserved - see section Security Consideration in this article. Assuming your u-boot has the hash command available, or that you can re-compile it with CONFIG_CMD_HASH=y, you could use an SHA-256 hash for verifying that your image was properly transferred: On a Linux TFTP server: # create an image for the purpose of the example echo "Binary Image" > image.bin # display sha256 hash for image.bin sha256sum -b image.bin 36949f85f1bff0d5d1dd5fcfdfd725e919b0ee64be24f7f3ccfb53908fd09550 *image.bin # create a file containing the hash in binary # credits: sha256sum -b image.bin | xxd -r -p > image.bin.sha256sum.bin # display content of binary file hexdump -C image.bin.sha256sum.bin 00000000 36 94 9f 85 f1 bf f0 d5 d1 dd 5f cf df d7 25 e9 |6........._...%.| 00000010 19 b0 ee 64 be 24 f7 f3 cc fb 53 90 8f d0 95 50 |...d.$....S....P| 00000020 On your u-boot system (using the memory layout available on my Alwinner H5 system here): # 0x40080000: address where image.bin will be transfered # 0x40090000: address where image.bin.sha256sum.bin will be transfrered # 0x40090000: address where the sha256 has will be computed by u-boot on the 13 bytes of image.bin # clearing memory mw.b 0x40080000 0 0x2000 mw.b 0x40090000 0 0x20 mw.b 0x400A0000 0 0x20 md.b 0x40080000 0x20 40080000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 40080010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ md.b 0x40090000 0x20 40090000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 40090010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ md.b 0x400A0000 0x20 400a0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 400a0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ tftp 0x40080000 image.bin Using ethernet#1c30000 device TFTP from server 192.168.1.22; our IP address is 192.168.1.2 Filename 'image.bin'. Load address: 0x40080000 Loading: # 5.9 KiB/s done Bytes transferred = 13 (d hex) tftp 0x40090000 image.bin.sha256sum.bin Using ethernet#1c30000 device TFTP from server 192.168.1.22; our IP address is 192.168.1.2 Filename 'image.bin.sha256sum.bin'. Load address: 0x40090000 Loading: # 15.6 KiB/s done Bytes transferred = 32 (20 hex) md.b 0x40090000 0x20 40090000: 36 94 9f 85 f1 bf f0 d5 d1 dd 5f cf df d7 25 e9 6........._...%. 40090010: 19 b0 ee 64 be 24 f7 f3 cc fb 53 90 8f d0 95 50 ...d.$....S....P hash sha256 0x40080000 0x0d *0x400A0000 sha256 for 40080000 ... 4008000c ==> 36949f85f1bff0d5d1dd5fcfdfd725e919b0ee64be24f7f3ccfb53908fd09550 cmp.b 0x40090000 0x400A0000 0x20 Total of 32 byte(s) were the same echo $? 0 In the case image.bin and/or image.bin.sha256sum.bin would have been improperly transferred, the chances that the computed sha256 would match the transferred one are extremely unlikely - using SHA-512 would make this even more unlikely. The outcome would have been in the case of an incorrect transfer: echo $? 1 In real life, this would be more practical to transfer an image with a fixed, maximum length, for example padded with zeroes, so that a u-boot script responsible for validating the transferred image would use a fixed length, say 8 KiB, that is 0x2000 bytes. ls -lgG image.bin -rw-rw-r-- 1 13 Dec 17 20:34 image.bin dd if=/dev/zero of=image.bin bs=8K count=1 oflag=append ls -lgG image.bin -rw-rw-r-- 1 8192 Dec 17 21:03 image.bin hexdump -C image.bin 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00002000 The correct u-boot command to use for computing the hash would be: hash sha256 0x40080000 0x2000 *0x400A0000 And a new binary file containing the new hash would of course have to be created as well: sha256sum -b image.bin | xxd -r -p > image.bin.sha256sum.bin I used two files for the purpose of the example, but you could just append image.bin.sha256sum.bin to image.bin and transfer one single file. You would have to replace 0x400A0000 by 0x40082000 in the hash and cmp commands. I hope this helps.
The tftp command returns true if it succeeds. So you could write: tftp ${rootfs_image} && mmc write ${loadaddr} ${blk} ${cnt} Now mmc write will only be executed if the tftp command succeeds.
Crafting an ELF file using linker scripts without zero-initialized blocks between sections
I am trying to craft a linker-command script to be bootable by legacy grub (using multiboot). I am having difficulty getting the multiboot header in the required location (within the first 8192 bytes). My script looks something like: SECTIONS { .multiboot : { __multiboot_header = .; *(.multiboot) } .text 0x00100000 : { *(.text*) *(.rodata) } /* ... remainder of script ... */ } Overall, my objective is to have my custom executable loaded by the bootloader after the first 1MiB of physical memory; the address as part of the .text section declaration seems to have done this as I expected. Reading the ELF header gives the entry point as: $ readelf -h kernel.elf | grep Entry Entry point address: 0x100000 However, in doing so I seem to have also increased the file by this much. $ ls -l file.elf -rwxr-xr-x 1 user user 1049960 May 13 02:20 file.elf The area between the ELF header and the .text section is initialized to zeros. $ hexdump -C file.elf 00000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 02 00 03 00 01 00 00 00 00 00 10 00 34 00 00 00 |............4...| 00000020 00 04 10 00 00 00 00 00 34 00 20 00 02 00 28 00 |........4. ...(.| 00000030 09 00 08 00 01 00 00 00 00 00 00 00 00 00 00 00 |................| 00000040 00 00 00 00 f8 00 10 00 f8 f0 4e 00 07 00 00 00 |..........N.....| 00000050 00 00 20 00 51 e5 74 64 00 00 00 00 00 00 00 00 |.. .Q.td........| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 |................| 00000070 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00100000 8b 25 f8 f0 4e 00 50 53 e8 66 00 00 00 fa f4 eb |.%..N.PS.f......| 00100010 fc 55 89 e5 53 83 ec 10 c7 45 f8 00 00 00 00 eb |.U..S....E......| 00100020 38 a1 f4 00 10 00 8b 55 f8 01 d2 01 d0 8b 15 f4 |8......U........| Also, although readelf -s reports that __multiboot_header has a value of 0x0 (which should be the address of the structure since it was defined at the same point it was mentioned in the linker file, right?): $ readelf -s kernel.elf | grep multiboot 22: 00000000 0 NOTYPE GLOBAL DEFAULT 1 __multiboot_header The output of readelf -S seems to conflict: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 1] .multiboot PROGBITS 00000000 1000f8 00000c 00 0 0 1 [ 2] .text PROGBITS 00100000 100000 000096 00 AX 0 0 1 Which implies that the .multiboot section is actually inside the .text section. If I offset into the file by 0x1000f8 then I can find the structure, however, I am not sure where the offset came from. tl;dr 1) How can I ensure a specific data structure is within the first 8192 bytes of the output file? 2) How can I specify the load address without inflating the output binary with large gaps of zero-initialized blocks?
The elf file format is generated by its own rules, how it stores the information is not directly influenced by the linker file (e.g. at what offsets the sections are stored must not correlate with their location at lifetime in memory). It's the memory layout which is described by the SECTIONS command in your linker file, and the elf file format describes this layout... You need a elf capable loader to load the individual sections into the target locations. To get a flat binary file which can be loaded 1:1 into memory, use objcopy (e.g. something like objcopy -O binary myfile.elf myfile.bin). The layout of that file is directly influenced by your linker script, and the content of the .multiboot section should be really at offset 0.
Failed to compile or link yasm program that call c function [duplicate]
This question already has an answer here: Can't run executable linked with libc (1 answer) Closed 2 years ago. When try to call c function from assembly code (yasm) on linux (x86-64), it failed to execute. Code function_call_c.asm: ; yasm assembly program, instruction - call c function ; compile: yasm -f elf64 function_call_c.asm -g dwarf2 && ld function_call_c.o -lc ; execute: ./a.out section .data msg_format db "hello" section .text extern printf global _start _start: lea rdi, [msg_format] call printf _exit: ; exit mov eax,1 mov ebx,5 int 0x80 Compile: yasm -f elf64 function_call_c.asm -g dwarf2 && ld function_call_c.o -lc When execute: It tips: bash: ./a.out: No such file or directory but a.out do exists, and has execution permission. Using objdump, get information of executable: a.out: file format elf64-x86-64 Disassembly of section .interp: 0000000000400158 <.interp>: 400158: 2f (bad) 400159: 6c insb (%dx),%es:(%rdi) 40015a: 69 62 2f 6c 64 36 34 imul $0x3436646c,0x2f(%rdx),%esp 400161: 2e 73 6f jae,pn 4001d3 <printf#plt-0x4d> 400164: 2e 31 00 xor %eax,%cs:(%rax) Disassembly of section .hash: 0000000000400168 <.hash>: 400168: 01 00 add %eax,(%rax) 40016a: 00 00 add %al,(%rax) 40016c: 02 00 add (%rax),%al 40016e: 00 00 add %al,(%rax) 400170: 01 00 add %eax,(%rax) ... Disassembly of section .dynsym: 0000000000400180 <.dynsym>: ... 400198: 0b 00 or (%rax),%eax 40019a: 00 00 add %al,(%rax) 40019c: 12 00 adc (%rax),%al ... Disassembly of section .dynstr: 00000000004001b0 <.dynstr>: 4001b0: 00 6c 69 62 add %ch,0x62(%rcx,%rbp,2) 4001b4: 63 2e movslq (%rsi),%ebp 4001b6: 73 6f jae 400227 <printf#plt+0x7> 4001b8: 2e 36 00 70 72 cs add %dh,%cs:%ss:0x72(%rax) 4001bd: 69 6e 74 66 00 47 4c imul $0x4c470066,0x74(%rsi),%ebp 4001c4: 49 rex.WB 4001c5: 42 rex.X 4001c6: 43 5f rex.XB pop %r15 4001c8: 32 2e xor (%rsi),%ch 4001ca: 32 2e xor (%rsi),%ch 4001cc: 35 .byte 0x35 ... Disassembly of section .gnu.version: 00000000004001ce <.gnu.version>: 4001ce: 00 00 add %al,(%rax) 4001d0: 02 00 add (%rax),%al Disassembly of section .gnu.version_r: 00000000004001d8 <.gnu.version_r>: 4001d8: 01 00 add %eax,(%rax) 4001da: 01 00 add %eax,(%rax) 4001dc: 01 00 add %eax,(%rax) 4001de: 00 00 add %al,(%rax) 4001e0: 10 00 adc %al,(%rax) 4001e2: 00 00 add %al,(%rax) 4001e4: 00 00 add %al,(%rax) 4001e6: 00 00 add %al,(%rax) 4001e8: 75 1a jne 400204 <printf#plt-0x1c> 4001ea: 69 09 00 00 02 00 imul $0x20000,(%rcx),%ecx 4001f0: 12 00 adc (%rax),%al 4001f2: 00 00 add %al,(%rax) 4001f4: 00 00 add %al,(%rax) ... Disassembly of section .rela.plt: 00000000004001f8 <.rela.plt>: 4001f8: a8 03 test $0x3,%al 4001fa: 60 (bad) 4001fb: 00 00 add %al,(%rax) 4001fd: 00 00 add %al,(%rax) 4001ff: 00 07 add %al,(%rdi) 400201: 00 00 add %al,(%rax) 400203: 00 01 add %al,(%rcx) ... Disassembly of section .plt: 0000000000400210 <printf#plt-0x10>: 400210: ff 35 82 01 20 00 pushq 0x200182(%rip) # 600398 <_GLOBAL_OFFSET_TABLE_+0x8> 400216: ff 25 84 01 20 00 jmpq *0x200184(%rip) # 6003a0 <_GLOBAL_OFFSET_TABLE_+0x10> 40021c: 0f 1f 40 00 nopl 0x0(%rax) 0000000000400220 <printf#plt>: 400220: ff 25 82 01 20 00 jmpq *0x200182(%rip) # 6003a8 <_GLOBAL_OFFSET_TABLE_+0x18> 400226: 68 00 00 00 00 pushq $0x0 40022b: e9 e0 ff ff ff jmpq 400210 <printf#plt-0x10> Disassembly of section .text: 0000000000400230 <_start>: 400230: 48 8d 3c 25 b0 03 60 lea 0x6003b0,%rdi 400237: 00 400238: e8 e3 ff ff ff callq 400220 <printf#plt> 000000000040023d <_exit>: 40023d: b8 01 00 00 00 mov $0x1,%eax 400242: bb 05 00 00 00 mov $0x5,%ebx 400247: cd 80 int $0x80 Disassembly of section .dynamic: 0000000000600250 <_DYNAMIC>: 600250: 01 00 add %eax,(%rax) 600252: 00 00 add %al,(%rax) 600254: 00 00 add %al,(%rax) 600256: 00 00 add %al,(%rax) 600258: 01 00 add %eax,(%rax) 60025a: 00 00 add %al,(%rax) 60025c: 00 00 add %al,(%rax) 60025e: 00 00 add %al,(%rax) 600260: 04 00 add $0x0,%al 600262: 00 00 add %al,(%rax) 600264: 00 00 add %al,(%rax) 600266: 00 00 add %al,(%rax) 600268: 68 01 40 00 00 pushq $0x4001 60026d: 00 00 add %al,(%rax) 60026f: 00 05 00 00 00 00 add %al,0x0(%rip) # 600275 <_DYNAMIC+0x25> 600275: 00 00 add %al,(%rax) 600277: 00 b0 01 40 00 00 add %dh,0x4001(%rax) 60027d: 00 00 add %al,(%rax) 60027f: 00 06 add %al,(%rsi) 600281: 00 00 add %al,(%rax) 600283: 00 00 add %al,(%rax) 600285: 00 00 add %al,(%rax) 600287: 00 80 01 40 00 00 add %al,0x4001(%rax) 60028d: 00 00 add %al,(%rax) 60028f: 00 0a add %cl,(%rdx) 600291: 00 00 add %al,(%rax) 600293: 00 00 add %al,(%rax) 600295: 00 00 add %al,(%rax) 600297: 00 1e add %bl,(%rsi) 600299: 00 00 add %al,(%rax) 60029b: 00 00 add %al,(%rax) 60029d: 00 00 add %al,(%rax) 60029f: 00 0b add %cl,(%rbx) 6002a1: 00 00 add %al,(%rax) 6002a3: 00 00 add %al,(%rax) 6002a5: 00 00 add %al,(%rax) 6002a7: 00 18 add %bl,(%rax) 6002a9: 00 00 add %al,(%rax) 6002ab: 00 00 add %al,(%rax) 6002ad: 00 00 add %al,(%rax) 6002af: 00 15 00 00 00 00 add %dl,0x0(%rip) # 6002b5 <_DYNAMIC+0x65> ... 6002bd: 00 00 add %al,(%rax) 6002bf: 00 03 add %al,(%rbx) 6002c1: 00 00 add %al,(%rax) 6002c3: 00 00 add %al,(%rax) 6002c5: 00 00 add %al,(%rax) 6002c7: 00 90 03 60 00 00 add %dl,0x6003(%rax) 6002cd: 00 00 add %al,(%rax) 6002cf: 00 02 add %al,(%rdx) 6002d1: 00 00 add %al,(%rax) 6002d3: 00 00 add %al,(%rax) 6002d5: 00 00 add %al,(%rax) 6002d7: 00 18 add %bl,(%rax) 6002d9: 00 00 add %al,(%rax) 6002db: 00 00 add %al,(%rax) 6002dd: 00 00 add %al,(%rax) 6002df: 00 14 00 add %dl,(%rax,%rax,1) 6002e2: 00 00 add %al,(%rax) 6002e4: 00 00 add %al,(%rax) 6002e6: 00 00 add %al,(%rax) 6002e8: 07 (bad) 6002e9: 00 00 add %al,(%rax) 6002eb: 00 00 add %al,(%rax) 6002ed: 00 00 add %al,(%rax) 6002ef: 00 17 add %dl,(%rdi) 6002f1: 00 00 add %al,(%rax) 6002f3: 00 00 add %al,(%rax) 6002f5: 00 00 add %al,(%rax) 6002f7: 00 f8 add %bh,%al 6002f9: 01 40 00 add %eax,0x0(%rax) 6002fc: 00 00 add %al,(%rax) 6002fe: 00 00 add %al,(%rax) 600300: fe (bad) 600301: ff (bad) 600302: ff 6f 00 ljmpq *0x0(%rdi) 600305: 00 00 add %al,(%rax) 600307: 00 d8 add %bl,%al 600309: 01 40 00 add %eax,0x0(%rax) 60030c: 00 00 add %al,(%rax) 60030e: 00 00 add %al,(%rax) 600310: ff (bad) 600311: ff (bad) 600312: ff 6f 00 ljmpq *0x0(%rdi) 600315: 00 00 add %al,(%rax) 600317: 00 01 add %al,(%rcx) 600319: 00 00 add %al,(%rax) 60031b: 00 00 add %al,(%rax) 60031d: 00 00 add %al,(%rax) 60031f: 00 f0 add %dh,%al 600321: ff (bad) 600322: ff 6f 00 ljmpq *0x0(%rdi) 600325: 00 00 add %al,(%rax) 600327: 00 ce add %cl,%dh 600329: 01 40 00 add %eax,0x0(%rax) ... Disassembly of section .got.plt: 0000000000600390 <_GLOBAL_OFFSET_TABLE_>: 600390: 50 push %rax 600391: 02 60 00 add 0x0(%rax),%ah ... 6003a8: 26 02 40 00 add %es:0x0(%rax),%al 6003ac: 00 00 add %al,(%rax) ... Disassembly of section .data: 00000000006003b0 <msg_format>: 6003b0: 68 65 6c 6c 6f pushq $0x6f6c6c65 Disassembly of section .debug_aranges: 0000000000000000 <.debug_aranges>: 0: 2c 00 sub $0x0,%al 2: 00 00 add %al,(%rax) 4: 02 00 add (%rax),%al 6: 00 00 add %al,(%rax) 8: 00 00 add %al,(%rax) a: 08 00 or %al,(%rax) c: 00 00 add %al,(%rax) e: 00 00 add %al,(%rax) 10: 30 02 xor %al,(%rdx) 12: 40 00 00 add %al,(%rax) 15: 00 00 add %al,(%rax) 17: 00 19 add %bl,(%rcx) ... Disassembly of section .debug_info: 0000000000000000 <.debug_info>: 0: 85 00 test %eax,(%rax) 2: 00 00 add %al,(%rax) 4: 02 00 add (%rax),%al 6: 00 00 add %al,(%rax) 8: 00 00 add %al,(%rax) a: 08 01 or %al,(%rcx) c: 00 00 add %al,(%rax) e: 00 00 add %al,(%rax) 10: 30 02 xor %al,(%rdx) 12: 40 00 00 add %al,(%rax) 15: 00 00 add %al,(%rax) 17: 00 49 02 add %cl,0x2(%rcx) 1a: 40 00 00 add %al,(%rax) 1d: 00 00 add %al,(%rax) 1f: 00 66 75 add %ah,0x75(%rsi) 22: 6e outsb %ds:(%rsi),(%dx) 23: 63 74 69 6f movslq 0x6f(%rcx,%rbp,2),%esi 27: 6e outsb %ds:(%rsi),(%dx) 28: 5f pop %rdi 29: 63 61 6c movslq 0x6c(%rcx),%esp 2c: 6c insb (%dx),%es:(%rdi) 2d: 5f pop %rdi 2e: 63 2e movslq (%rsi),%ebp 30: 61 (bad) 31: 73 6d jae a0 <printf#plt-0x400180> 33: 00 2f add %ch,(%rdi) 35: 6d insl (%dx),%es:(%rdi) 36: 6e outsb %ds:(%rsi),(%dx) 37: 74 2f je 68 <printf#plt-0x4001b8> 39: 73 74 jae af <printf#plt-0x400171> 3b: 61 (bad) 3c: 72 2f jb 6d <printf#plt-0x4001b3> 3e: 67 69 74 5f 72 65 70 imul $0x736f7065,0x72(%edi,%ebx,2),%esi 45: 6f 73 47: 69 74 6f 72 79 2f 77 imul $0x6f772f79,0x72(%rdi,%rbp,2),%esi 4e: 6f 4f: 72 6b jb bc <printf#plt-0x400164> 51: 73 70 jae c3 <printf#plt-0x40015d> 53: 61 (bad) 54: 63 65 2f movslq 0x2f(%rbp),%esp 57: 61 (bad) 58: 73 73 jae cd <printf#plt-0x400153> 5a: 65 gs 5b: 6d insl (%dx),%es:(%rdi) 5c: 62 (bad) 5d: 6c insb (%dx),%es:(%rdi) 5e: 79 5f jns bf <printf#plt-0x400161> 60: 77 6f ja d1 <printf#plt-0x40014f> 62: 72 6b jb cf <printf#plt-0x400151> 64: 70 6c jo d2 <printf#plt-0x40014e> 66: 61 (bad) 67: 63 65 2f movslq 0x2f(%rbp),%esp 6a: 79 61 jns cd <printf#plt-0x400153> 6c: 73 6d jae db <printf#plt-0x400145> 6e: 2f (bad) 6f: 69 6e 73 74 72 75 63 imul $0x63757274,0x73(%rsi),%ebp 76: 74 69 je e1 <printf#plt-0x40013f> 78: 6f outsl %ds:(%rsi),(%dx) 79: 6e outsb %ds:(%rsi),(%dx) 7a: 2f (bad) 7b: 00 79 61 add %bh,0x61(%rcx) 7e: 73 6d jae ed <printf#plt-0x400133> 80: 20 31 and %dh,(%rcx) 82: 2e 32 2e xor %cs:(%rsi),%ch 85: 30 00 xor %al,(%rax) 87: 01 .byte 0x1 88: 80 .byte 0x80 Disassembly of section .debug_abbrev: 0000000000000000 <.debug_abbrev>: 0: 01 11 add %edx,(%rcx) 2: 00 10 add %dl,(%rax) 4: 06 (bad) 5: 11 01 adc %eax,(%rcx) 7: 12 01 adc (%rcx),%al 9: 03 08 add (%rax),%ecx b: 1b 08 sbb (%rax),%ecx d: 25 08 13 05 00 and $0x51308,%eax ... Disassembly of section .debug_line: 0000000000000000 <.debug_line>: 0: 47 00 00 rex.RXB add %r8b,(%r8) 3: 00 02 add %al,(%rdx) 5: 00 2a add %ch,(%rdx) 7: 00 00 add %al,(%rax) 9: 00 01 add %al,(%rcx) b: 01 fb add %edi,%ebx d: 0e (bad) e: 0d 00 01 01 01 or $0x1010100,%eax 13: 01 00 add %eax,(%rax) 15: 00 00 add %al,(%rax) 17: 01 00 add %eax,(%rax) 19: 00 01 add %al,(%rcx) 1b: 00 66 75 add %ah,0x75(%rsi) 1e: 6e outsb %ds:(%rsi),(%dx) 1f: 63 74 69 6f movslq 0x6f(%rcx,%rbp,2),%esi 23: 6e outsb %ds:(%rsi),(%dx) 24: 5f pop %rdi 25: 63 61 6c movslq 0x6c(%rcx),%esp 28: 6c insb (%dx),%es:(%rdi) 29: 5f pop %rdi 2a: 63 2e movslq (%rsi),%ebp 2c: 61 (bad) 2d: 73 6d jae 9c <printf#plt-0x400184> 2f: 00 00 add %al,(%rax) 31: 00 00 add %al,(%rax) 33: 00 00 add %al,(%rax) 35: 09 02 or %eax,(%rdx) 37: 30 02 xor %al,(%rdx) 39: 40 00 00 add %al,(%rax) 3c: 00 00 add %al,(%rax) 3e: 00 03 add %al,(%rbx) 40: 0c 01 or $0x1,%al 42: 83 5d 59 59 sbbl $0x59,0x59(%rbp) 46: 02 02 add (%rdx),%al 48: 00 01 add %al,(%rcx) 4a: 01 .byte 0x1 Using readelf, get information of executable: ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x400230 Start of program headers: 64 (bytes into file) Start of section headers: 1432 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 5 Size of section headers: 64 (bytes) Number of section headers: 21 Section header string table index: 18 Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000400158 00000158 000000000000000f 0000000000000000 A 0 0 1 [ 2] .hash HASH 0000000000400168 00000168 0000000000000014 0000000000000004 A 3 0 8 [ 3] .dynsym DYNSYM 0000000000400180 00000180 0000000000000030 0000000000000018 A 4 1 8 [ 4] .dynstr STRTAB 00000000004001b0 000001b0 000000000000001e 0000000000000000 A 0 0 1 [ 5] .gnu.version VERSYM 00000000004001ce 000001ce 0000000000000004 0000000000000002 A 3 0 2 [ 6] .gnu.version_r VERNEED 00000000004001d8 000001d8 0000000000000020 0000000000000000 A 4 1 8 [ 7] .rela.plt RELA 00000000004001f8 000001f8 0000000000000018 0000000000000018 A 3 8 8 [ 8] .plt PROGBITS 0000000000400210 00000210 0000000000000020 0000000000000010 AX 0 0 16 [ 9] .text PROGBITS 0000000000400230 00000230 0000000000000019 0000000000000000 AX 0 0 16 [10] .eh_frame PROGBITS 0000000000400250 00000250 0000000000000000 0000000000000000 A 0 0 8 [11] .dynamic DYNAMIC 0000000000600250 00000250 0000000000000140 0000000000000010 WA 4 0 8 [12] .got.plt PROGBITS 0000000000600390 00000390 0000000000000020 0000000000000008 WA 0 0 8 [13] .data PROGBITS 00000000006003b0 000003b0 0000000000000005 0000000000000000 WA 0 0 4 [14] .debug_aranges PROGBITS 0000000000000000 000003c0 0000000000000030 0000000000000000 0 0 16 [15] .debug_info PROGBITS 0000000000000000 000003f0 0000000000000089 0000000000000000 0 0 1 [16] .debug_abbrev PROGBITS 0000000000000000 00000479 0000000000000014 0000000000000000 0 0 1 [17] .debug_line PROGBITS 0000000000000000 0000048d 000000000000004b 0000000000000000 0 0 1 [18] .shstrtab STRTAB 0000000000000000 000004d8 00000000000000bc 0000000000000000 0 0 1 [19] .symtab SYMTAB 0000000000000000 00000ad8 00000000000002b8 0000000000000018 20 24 8 [20] .strtab STRTAB 0000000000000000 00000d90 0000000000000078 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x0000000000000118 0x0000000000000118 R E 8 INTERP 0x0000000000000158 0x0000000000400158 0x0000000000400158 0x000000000000000f 0x000000000000000f R 1 [Requesting program interpreter: /lib/ld64.so.1] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x0000000000000250 0x0000000000000250 R E 200000 LOAD 0x0000000000000250 0x0000000000600250 0x0000000000600250 0x0000000000000165 0x0000000000000165 RW 200000 DYNAMIC 0x0000000000000250 0x0000000000600250 0x0000000000600250 0x0000000000000140 0x0000000000000140 RW 8 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.plt .plt .text 03 .dynamic .got.plt .data 04 .dynamic Dynamic section at offset 0x250 contains 15 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x0000000000000004 (HASH) 0x400168 0x0000000000000005 (STRTAB) 0x4001b0 0x0000000000000006 (SYMTAB) 0x400180 0x000000000000000a (STRSZ) 30 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000015 (DEBUG) 0x0 0x0000000000000003 (PLTGOT) 0x600390 0x0000000000000002 (PLTRELSZ) 24 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x4001f8 0x000000006ffffffe (VERNEED) 0x4001d8 0x000000006fffffff (VERNEEDNUM) 1 0x000000006ffffff0 (VERSYM) 0x4001ce 0x0000000000000000 (NULL) 0x0 Relocation section '.rela.plt' at offset 0x1f8 contains 1 entries: Offset Info Type Sym. Value Sym. Name + Addend 0000006003a8 000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf + 0 The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported. Symbol table '.dynsym' contains 2 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf#GLIBC_2.2.5 (2) Symbol table '.symtab' contains 29 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400158 0 SECTION LOCAL DEFAULT 1 2: 0000000000400168 0 SECTION LOCAL DEFAULT 2 3: 0000000000400180 0 SECTION LOCAL DEFAULT 3 4: 00000000004001b0 0 SECTION LOCAL DEFAULT 4 5: 00000000004001ce 0 SECTION LOCAL DEFAULT 5 6: 00000000004001d8 0 SECTION LOCAL DEFAULT 6 7: 00000000004001f8 0 SECTION LOCAL DEFAULT 7 8: 0000000000400210 0 SECTION LOCAL DEFAULT 8 9: 0000000000400230 0 SECTION LOCAL DEFAULT 9 10: 0000000000400250 0 SECTION LOCAL DEFAULT 10 11: 0000000000600250 0 SECTION LOCAL DEFAULT 11 12: 0000000000600390 0 SECTION LOCAL DEFAULT 12 13: 00000000006003b0 0 SECTION LOCAL DEFAULT 13 14: 0000000000000000 0 SECTION LOCAL DEFAULT 14 15: 0000000000000000 0 SECTION LOCAL DEFAULT 15 16: 0000000000000000 0 SECTION LOCAL DEFAULT 16 17: 0000000000000000 0 SECTION LOCAL DEFAULT 17 18: 0000000000000000 0 FILE LOCAL DEFAULT ABS function_call_c.asm 19: 000000000040023d 0 NOTYPE LOCAL DEFAULT 9 _exit 20: 00000000006003b0 0 NOTYPE LOCAL DEFAULT 13 msg_format 21: 0000000000000000 0 FILE LOCAL DEFAULT ABS 22: 0000000000600250 0 OBJECT LOCAL DEFAULT 11 _DYNAMIC 23: 0000000000600390 0 OBJECT LOCAL DEFAULT 12 _GLOBAL_OFFSET_TABLE_ 24: 00000000006003b5 0 NOTYPE GLOBAL DEFAULT 13 _edata 25: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf##GLIBC_2.2.5 26: 00000000006003b8 0 NOTYPE GLOBAL DEFAULT 13 _end 27: 0000000000400230 0 NOTYPE GLOBAL DEFAULT 9 _start 28: 00000000006003b5 0 NOTYPE GLOBAL DEFAULT 13 __bss_start Histogram for bucket list length (total of 1 buckets): Length Number % of total Coverage 0 0 ( 0.0%) 1 1 (100.0%) 100.0% Version symbols section '.gnu.version' contains 2 entries: Addr: 00000000004001ce Offset: 0x0001ce Link: 3 (.dynsym) 000: 0 (*local*) 2 (GLIBC_2.2.5) Version needs section '.gnu.version_r' contains 1 entries: Addr: 0x00000000004001d8 Offset: 0x0001d8 Link: 4 (.dynstr) 000000: Version: 1 File: libc.so.6 Cnt: 1 0x0010: Name: GLIBC_2.2.5 Flags: none Version: 2 The questions are: Why it failed to execute, is the code wrong? or I compiled it in a wrong way?
Just ran your example and encountered the same issue. The cause is my case was an incorrect dynamic linker (ELF interpreter). To verify this is the issue, type file ./a.out you should be getting something similiar to the following output: a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped ld's default choice of dynamic linker (/lib/ld64.so.1) doesn't exist on most Linux systems, hence the problem. You could use patchelf (apt-get install patchelf) and the following command to correct this: patchelf --set-interpreter [path_to_interpreter] ./a.out You can get the correct path you should use as the ELF interpreter by typing file /bin/ls - the standard dynamic linker path will be printed. (Also, readelf can print that and more). The best way is to use ld's -dynamic-linker flag to set the INTERP section in the elf header correctly in the first place. See also this answer for more details on building / linking asm into static or dynamic binaries, with or without libc.
(As suggested by #Peter Cordes, I'd like put an answer that summarize the comments under question & other answer, so that make it more clear for future searcher.) Issues in the original code & compile/link strategy: Better use main instead of _start. Reason: because (as originally mentioned in #Michael Petch's comment), the C runtime includes a _start label, this is conflict, when link using gcc. Even though this could be fixed via adding -nostartfiles option to gcc when link, but a simple gcc xxx.o is simpler. So, just use main instead of _start. Exit main via ret instead of int 0x80. Reason: because (as originally mentioned in #Michael Petch's comment), ret will help to flush the stdout, while int 0x80 won't, so using int 0x80 won't see the hello world in console. Calling C function exit is another solution, but it's an extra function call to c, so using ret is more efficient, it will return to _start from c runtime. Better link via gcc instead of ld. Reason: because (as mentioned in #Peter Cordes and #Michael Petch's comments), C runtime is being included by default in gcc, so you don't need to add option like -lc when using gcc. But ld don't include C runtime. So, again, using gcc makes it simpler. For more details, please refer to the comments under question and other answer. (So, according to above explanation.) Steps to fix the issue: Change _start to main, in assembly source code, Exit program via ret instead of int 0x80. Compile via yasm, e.g yasm -f elf64 function_call_c.asm -g dwarf2 Link via gcc, e.g gcc function_call_c.o (And here is the new version of code.) function_call_c.asm: ; yasm assembly program, instruction - call c function ; compile: yasm -f elf64 function_call_c.asm -g dwarf2 && gcc function_call_c.o ; execute: ./a.out ; check printed char count (immediately after execution): echo $? section .data msg_format db 'hello world',0x0A,0 section .text extern printf extern exit global main main: mov rax, 0 lea rdi, [msg_format] call printf _exit: ; eax now contains count of chars printed, due to previous 'printf' call, ret; return from main, this will flush the output,
Write header with C program?
In order to boot a Linux kernel on an embedded device I have to tag the kernel with a special header. The program used to tag the kernel is provided by the manufacture of the device as a 32-bit binary only. This is very annoying as I have to install hundreds of megabytes libraries on my 64-bit system only to tag a kernel with few bytes. This is how the kernel is tagged: $./mkimage -f kernel.cfg -d zImage_without_header zImage kernel.cfg: ########################################################## #ENCINFO.CFG # # information and command for encode the Linux zImage ########################################################## # Magic number for the ImageHeader, use this to seach start of the Image Header # MAGIC_NUMBER 0x27051956 #operation system type OS_TYPE linux #cpu architecture type CPU_ARCH arm #image type IMAGE_TYPE kernel #compress type COMPRESS_TYPE gzip # DATALOAD_ADDRESS 0x00008000 # ENTRY_ADDRESS 0x00008000 #image name string IMAGE_NAME kernel.img #model name string MODEL_NAME DNS-313 # version string VERSION 1.00b18 # mac address string MAC_ADDRESS FF-FF-FF-FF-FF-FF #the beginning offset of writing header START_OFFSET 0x00 #the end offset of writing header END_OFFSET 0xFF #whether overwrite OVERWRITE n The mkimage binary is different from the mkimage that is available from e.g. the Debian repository, that one will not work for my device. I have tried to create a 1MB file and tagged it to display the header: $dd if=/dev/zero bs=1k count=1024 of=zImage_without_header $./mkimage -f kernel.cfg -d zImage_without_header zImage output from last command: Magic Number: 27051956 Image Name: kernel.img Created: Wed May 2 17:40:43 2012 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 1048576 Bytes = 1024.00 kB = 1.00 MB Load Address: 0x00008000 Entry Point: 0x00008000 Model Name: DNS-313 Version : 1.00b18 Mac Address: ff:ff:ff:ff:ff:ff $hexdump -C zImage output from last command: 00000000 27 05 19 56 [2c 83 53 d5] 4f a1 [55 7b 00 10 00 00] |'..V,.S.O.U{....| 00000010 00 00 80 00 00 00 80 00 [a7 38 ea 1c] 05 02 02 01 |.........8......| 00000020 6b 65 72 6e 65 6c 2e 69 6d 67 00 00 00 00 00 00 |kernel.img......| 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000040 44 4e 53 2d 33 31 33 00 00 00 00 00 00 00 00 00 |DNS-313.........| 00000050 31 2e 30 30 62 31 38 00 00 00 00 00 00 00 00 00 |1.00b18.........| 00000060 ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 |................| 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00100060 The kernels should always be tagged with a header like the one above as I do not need to change anything. The the values enclosed in brackets [] seem to change when the filesize does, but I do not know how. I think that the same thing could be accomplished with a small C program, but I am not sure where to start and how? Any suggestions or ideas are welcome.
It might be a long shot, but if you do not have access to the "mkimage" source code, you can try disassembling it with objdump and try to figure out what is going on : $ objdump -d ./mkimage